No catalogs available.
[AROS.git] / rom / hidds / ata_pci / probe.c
blob1836a8510327ed053ece82c8e8c15997be339183
1 /*
2 Copyright © 2004-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Hardware detection routine
6 Lang: English
7 */
9 #define DSATA(x)
11 #define __OOP_NOMETHODBASES__
13 #include <aros/asmcall.h>
14 #include <aros/bootloader.h>
15 #include <aros/debug.h>
16 #include <aros/symbolsets.h>
17 #include <asm/io.h>
18 #include <exec/lists.h>
19 #include <exec/rawfmt.h>
20 #include <hardware/ahci.h>
21 #include <hidd/ata.h>
22 #include <hidd/pci.h>
23 #include <oop/oop.h>
24 #include <proto/bootloader.h>
25 #include <proto/exec.h>
26 #include <proto/oop.h>
28 #include <string.h>
30 #include "bus_class.h"
31 #include "interface_pio.h"
32 #include "interface_dma.h"
33 #include "pci.h"
36 * Currently we support legacy ISA ports only on x86.
37 * This can change only if someone ports AROS to PowerPC
38 * retro-machine like PReP.
40 #ifdef __i386__
41 #define SUPPORT_LEGACY
42 #endif
43 #ifdef __x86_64__
44 #define SUPPORT_LEGACY
45 #endif
47 #define NAME_BUFFER 128
49 #define RANGESIZE0 8
50 #define RANGESIZE1 4
51 #define DMASIZE 16
53 /* static list of io/irqs that we can handle */
54 struct ata__legacybus
56 UWORD lb_Port;
57 UWORD lb_Alt;
58 UBYTE lb_IRQ;
59 UBYTE lb_ControllerID;
60 UBYTE lb_Bus;
61 const char *lb_Name;
64 static const struct ata__legacybus LegacyBuses[] =
66 {0x1f0, 0x3f4, 14, 0, 0, "ISA IDE0 primary channel" },
67 {0x170, 0x374, 15, 0, 1, "ISA IDE0 secondary channel"},
68 {0x168, 0x36c, 10, 1, 0, "ISA IDE1 primary channel" },
69 {0x1e8, 0x3ec, 11, 1, 1, "ISA IDE1 secondary channel"},
70 { 0, 0, 0, 0, 0, NULL }
73 #ifdef DO_SATA_HANDOFF
75 /* SATA handoff code needs timer */
77 static struct IORequest *OpenTimer(void)
79 struct MsgPort *p = CreateMsgPort();
81 if (NULL != p)
83 struct IORequest *io = CreateIORequest(p, sizeof(struct timerequest));
85 if (NULL != io)
87 if (0 == OpenDevice("timer.device", UNIT_MICROHZ, io, 0))
89 return io;
91 DeleteIORequest(io);
93 DeleteMsgPort(p);
96 return NULL;
99 static void CloseTimer(struct IORequest *tmr)
101 if (NULL != tmr)
103 struct MsgPort *p = tmr->io_Message.mn_ReplyPort;
105 CloseDevice(tmr);
106 DeleteIORequest(tmr);
107 DeleteMsgPort(p);
111 static void WaitTO(struct IORequest* tmr, ULONG secs, ULONG micro)
113 tmr->io_Command = TR_ADDREQUEST;
114 ((struct timerequest*)tmr)->tr_time.tv_secs = secs;
115 ((struct timerequest*)tmr)->tr_time.tv_micro = micro;
117 DoIO(tmr);
120 #endif
123 * PCI BUS ENUMERATOR
124 * collect ALL ata/ide capable devices (including SATA and other) and
125 * spawn concurrent tasks.
127 * This function is growing too large. It will shorten drasticly once this whole mess gets converted into c++
130 static
131 AROS_UFH3(void, ata_PCIEnumerator_h,
132 AROS_UFHA(struct Hook *, hook, A0),
133 AROS_UFHA(OOP_Object *, Device, A2),
134 AROS_UFHA(APTR, message,A1))
136 AROS_USERFUNC_INIT
138 struct ataBase *base = hook->h_Data;
139 OOP_Object *Driver;
140 struct PCIDeviceRef *devRef;
141 IPTR ProductID, VendorID, DMABase, DMASize, INTLine;
142 IPTR IOBase, IOAlt, IOSize, AltSize, SubClass, Interface;
143 int x;
144 CONST_STRPTR owner;
147 * obtain more or less useful data
149 OOP_GetAttr(Device, aHidd_PCIDevice_Driver , (IPTR *)&Driver);
150 OOP_GetAttr(Device, aHidd_PCIDevice_VendorID , &VendorID);
151 OOP_GetAttr(Device, aHidd_PCIDevice_ProductID, &ProductID);
152 OOP_GetAttr(Device, aHidd_PCIDevice_SubClass , &SubClass);
153 OOP_GetAttr(Device, aHidd_PCIDevice_Base4 , &DMABase);
154 OOP_GetAttr(Device, aHidd_PCIDevice_Size4 , &DMASize);
155 OOP_GetAttr(Device, aHidd_PCIDevice_Interface, &Interface);
157 D(bug("[PCI-ATA] ata_PCIEnumerator_h: Found IDE device %04x:%04x\n", VendorID, ProductID));
159 /* First check subclass */
160 if ((SubClass == PCI_SUBCLASS_SCSI) || (SubClass == PCI_SUBCLASS_SAS))
162 D(bug("[PCI-ATA] Unsupported subclass %d\n", SubClass));
163 return;
166 owner = HIDD_PCIDevice_Obtain(Device, base->lib.lib_Node.ln_Name);
167 if (owner)
169 D(bug("[PCI-ATA] Already owned by %s\n", owner));
170 return;
173 devRef = AllocMem(sizeof(struct PCIDeviceRef), MEMF_ANY);
174 if (!devRef)
176 D(bug("[PCI-ATA] Failed to allocate reference structure\n"));
177 return;
180 devRef->ref_Device = Device;
181 devRef->ref_Count = 0;
184 * SATA controllers may need a special treatment before becoming usable.
185 * The machine's firmware (EFI on Mac) may operate them in native AHCI mode
186 * and not set up legacy mode by itself.
187 * In this case we have to do it ourselves.
188 * This code is based on incomplete ahci.device source code by DissyOfCRN.
189 * CHECKME: In order to work on PPC it uses explicit little-endian I/O,
190 * assuming AHCI register file is always little-endian. Is it correct?
192 if (SubClass == PCI_SUBCLASS_SATA)
194 APTR hba_phys = NULL;
195 IPTR hba_size = 0;
196 volatile struct ahci_hwhba *hwhba;
197 ULONG ghc, cap;
199 OOP_GetAttr(Device, aHidd_PCIDevice_Base5, (IPTR *)&hba_phys);
200 OOP_GetAttr(Device, aHidd_PCIDevice_Size5, &hba_size);
202 DSATA(bug("[PCI-ATA] Device %04x:%04x is a SATA device, HBA 0x%p, size 0x%p\n", VendorID, ProductID, hba_phys, hba_size));
204 hwhba = HIDD_PCIDriver_MapPCI(Driver, hba_phys, hba_size);
205 DSATA(bug("[PCI-ATA] Mapped at 0x%p\n", hwhba));
207 if (!hwhba)
209 DSATA(bug("[PCI-ATA] Mapping failed, device will be ignored\n"));
210 DeviceFree(devRef, base);
211 return;
214 cap = mmio_inl_le(&hwhba->cap);
215 ghc = mmio_inl_le(&hwhba->ghc);
216 DSATA(bug("[PCI-ATA] Capabilities: 0x%08X, host control: 0x%08X\n", cap, ghc));
219 * Some hardware may report GHC_AE to be zero, together with CAP_SAM set (indicating
220 * that the device doesn't support legacy IDE registers). Seems to be spec violation
221 * (the AHCI specification says that in this cases GHC_AE is read-only bit which is
222 * hardwired to 1).
223 * Attempting to drive such a hardware causes ata.device to freeze.
224 * This effect has been observed on Marvel 9172 controller (and some other HW,
225 * according to user reports, but nobody has ever provided a debug log).
227 if (cap & CAP_SAM)
229 DSATA(bug("[PCI-ATA] Legacy mode is not supported, device will be ignored\n"));
231 HIDD_PCIDriver_UnmapPCI(Driver, hba_phys, hba_size);
232 DeviceFree(devRef, base);
233 return;
236 if (ghc & GHC_AE)
238 DSATA(bug("[PCI-ATA] AHCI enabled\n"));
241 * This is ATA driver, not SATA driver, so i'd like to keep SATA-specific code
242 * at a minimum. None of tests revealed a real need for BIOS handoff, no BIOS
243 * was discovered to use controllers in SMI mode.
244 * However, if on some machine we have problems, we can try
245 * to #define this.
247 #ifdef DO_SATA_HANDOFF
248 ULONG version = mmio_inl_le(&hwhba->vs);
249 ULONG cap2 = mmio_inl_le(&hwhba->cap2);
251 DSATA(bug("[PCI-ATA] Version: 0x%08X, Cap2: 0x%08X\n", version, cap2));
253 if ((version >= AHCI_VERSION_1_20) && (cap2 && CAP2_BOH))
255 ULONG bohc;
257 DSATA(bug("[PCI-ATA] HBA supports BIOS/OS handoff\n"));
259 bohc = mmio_inl_le(&hwhba->bohc);
260 if (bohc && BOHC_BOS)
262 struct IORequest *timereq;
264 DSATA(bug("[PCI-ATA] Device owned by BIOS, performing handoff\n"));
267 * We need timer.device in order to perform delays.
268 * TODO: in ata_InitBus() it will be opened and closed again.
269 * This is not optimal, it could be opened and closed just once.
271 timereq = OpenTimer(base);
272 if (!timereq)
274 DSATA(bug("[PCI-ATA] Failed to open timer, can't perform handoff. Device will be ignored\n"));
276 HIDD_PCIDriver_UnmapPCI(Driver, hba_phys, hba_size);
277 DeviceFree(devRef, base);
278 return;
281 mmio_outl_le(bohc | BOHC_OOS, &hwhba->bohc);
282 /* Spin on BOHC_BOS bit FIXME: Possible dead lock. No maximum time given on AHCI1.3 specs... */
283 while (mmio_inl_le(&hwhba->bohc) & BOHC_BOS);
285 WaitTO(timereq, 0, 25000);
286 /* If after 25ms BOHC_BB bit is still set give bios a minimum of 2 seconds more time to run */
288 if (mmio_inl_le(&hwhba->bohc) & BOHC_BB)
290 DSATA(bug("[PCI-ATA] Delayed handoff, waiting...\n"));
291 ata_WaitTO(timereq, 2, 0);
294 DSATA(bug("[PCI-ATA] Handoff done\n"));
295 CloseTimer(timereq);
298 #endif
299 /* This resets GHC_AE bit, disabling AHCI */
300 mmio_outl_le(0, &hwhba->ghc);
303 HIDD_PCIDriver_UnmapPCI(Driver, (APTR)hwhba, hba_size);
307 * we can have up to two buses assigned to this device
309 for (x = 0; devRef != NULL && x < MAX_DEVICEBUSES; x++)
311 BYTE basePri = ATABUSNODEPRI_PROBED;
314 * obtain I/O bases and interrupt line
316 if ((Interface & (1 << (x << 1))) || SubClass != PCI_SUBCLASS_IDE)
318 switch (x)
320 case 0:
321 OOP_GetAttr(Device, aHidd_PCIDevice_Base0, &IOBase);
322 OOP_GetAttr(Device, aHidd_PCIDevice_Size0, &IOSize);
323 OOP_GetAttr(Device, aHidd_PCIDevice_Base1, &IOAlt);
324 OOP_GetAttr(Device, aHidd_PCIDevice_Size1, &AltSize);
325 break;
327 case 1:
328 OOP_GetAttr(Device, aHidd_PCIDevice_Base2, &IOBase);
329 OOP_GetAttr(Device, aHidd_PCIDevice_Size2, &IOSize);
330 OOP_GetAttr(Device, aHidd_PCIDevice_Base3, &IOAlt);
331 OOP_GetAttr(Device, aHidd_PCIDevice_Size3, &AltSize);
332 break;
334 OOP_GetAttr(Device, aHidd_PCIDevice_INTLine, &INTLine);
336 else if (LegacyBuses[base->legacycount].lb_ControllerID == 0)
338 IPTR isa_io_base;
340 OOP_GetAttr(Driver, aHidd_PCIDriver_IOBase, &isa_io_base);
341 D(bug("[PCI-ATA] Device using Legacy-Bus IOPorts @ 0x%p\n", isa_io_base));
343 IOBase = LegacyBuses[base->legacycount].lb_Port + isa_io_base;
344 IOAlt = LegacyBuses[base->legacycount].lb_Alt + isa_io_base;
345 INTLine = LegacyBuses[base->legacycount].lb_IRQ;
346 basePri = ATABUSNODEPRI_PROBEDLEGACY;
347 IOSize = RANGESIZE0;
348 AltSize = RANGESIZE1;
350 base->legacycount++;
352 else
354 D(bug("[PCI-ATA] Ran out of legacy buses\n"));
355 IOBase = 0;
358 if (IOBase != 0 && IOSize == RANGESIZE0 && AltSize == RANGESIZE1 &&
359 (DMASize >= DMASIZE || DMABase == 0 || SubClass == PCI_SUBCLASS_IDE))
361 struct ata_ProbedBus *probedbus;
362 STRPTR str[2];
363 int len;
365 D(bug("[PCI-ATA] ata_PCIEnumerator_h: Adding Bus %d - IRQ %d, IO: %x:%x, DMA: %x\n",
366 x, INTLine, IOBase, IOAlt, DMABase));
368 OOP_GetAttr(Device, aHidd_PCIDevice_SubClassDesc, (IPTR *)&str[0]);
369 str[1] = x ? "secondary" : "primary";
370 len = 14 + strlen(str[0]) + strlen(str[1]);
372 probedbus = AllocVec(sizeof(struct ata_ProbedBus) + len, MEMF_ANY);
373 if (probedbus)
375 IPTR dmaBase = DMABase ? DMABase + (x << 3) : 0;
376 STRPTR name = (char *)probedbus + sizeof(struct ata_ProbedBus);
378 RawDoFmt("PCI %s %s channel", (RAWARG)str, RAWFMTFUNC_STRING, name);
380 probedbus->atapb_Node.ln_Name = name;
381 probedbus->atapb_Node.ln_Type = basePri;
382 probedbus->atapb_Node.ln_Pri = basePri - (base->ata__buscount++);
383 probedbus->atapb_Device = devRef;
384 probedbus->atapb_Vendor = VendorID;
385 probedbus->atapb_Product = ProductID;
386 probedbus->atapb_BusNo = x;
387 probedbus->atapb_IOBase = IOBase;
388 probedbus->atapb_IOAlt = IOAlt;
389 probedbus->atapb_INTLine = INTLine;
390 probedbus->atapb_DMABase = dmaBase;
392 devRef->ref_Count++;
393 Enqueue((struct List *)&base->probedbuses, &probedbus->atapb_Node);
395 OOP_SetAttrsTags(Device, aHidd_PCIDevice_isIO, TRUE,
396 aHidd_PCIDevice_isMaster, DMABase != 0,
397 TAG_DONE);
401 if (!devRef->ref_Count)
403 DeviceFree(devRef, base);
404 devRef = NULL;
408 AROS_USERFUNC_EXIT
411 static CONST_STRPTR pciInterfaceIDs[] =
413 IID_Hidd_PCI,
414 IID_Hidd_PCIDevice,
415 IID_Hidd_PCIDriver,
416 NULL
419 /* We need no attributes for IID_Hidd_PCI, only methods */
420 #define ATTR_OFFSET 1
422 static const struct TagItem Requirements[] =
424 {tHidd_PCI_Class, PCI_CLASS_MASSSTORAGE},
425 {TAG_DONE, 0x00 }
429 * The manner in which this code is written can look a little bit overcomplicated.
430 * However it's just experimental attempt to write hardware scan routine which
431 * can be run more than once, and is hotplug-aware.
432 * In future this may assist implementation of "Rescan devices" functionality
433 * in SysExplorer (for example). This will provide a possibility to load and unload
434 * device drivers on the fly.
435 * For now it's just experiment... Don't pay much attention please. :)
437 static int ata_pci_Scan(struct ataBase *base)
439 OOP_Object *ata = OOP_NewObject(NULL, CLID_HW_ATA, NULL);
440 APTR BootLoaderBase;
441 struct ata_ProbedBus *probedbus;
442 BOOL scanpci = TRUE;
443 #ifdef SUPPORT_LEGACY
444 BOOL scanlegacy = TRUE;
445 #endif
447 /* First make sure that ATA subsystem is in place */
448 if (!ata)
449 return FALSE;
451 /* Prepare lists for probed/found ide buses */
452 NEWLIST(&base->probedbuses);
453 base->ata__buscount = 0;
454 base->legacycount = 0;
456 /* Obtain command line parameters */
457 BootLoaderBase = OpenResource("bootloader.resource");
458 D(bug("[PCI-ATA] BootloaderBase = %p\n", BootLoaderBase));
459 if (BootLoaderBase != NULL)
461 struct List *list;
462 struct Node *node;
464 list = (struct List *)GetBootInfo(BL_Args);
465 if (list)
467 ForeachNode(list, node)
469 if (strncmp(node->ln_Name, "ATA=", 4) == 0)
471 const char *cmdline = &node->ln_Name[4];
473 if (strstr(cmdline, "nopci"))
475 D(bug("[PCI-ATA] Disabling PCI device scan\n"));
476 scanpci = FALSE;
478 #ifdef SUPPORT_LEGACY
479 if (strstr(cmdline, "nolegacy"))
481 D(bug("[PCI-ATA] Disabling Legacy ports\n"));
482 scanlegacy = FALSE;
484 #endif
485 if (strstr(cmdline, "off"))
487 D(bug("[PCI-ATA] Disabling all ATA devices\n"));
488 #ifdef SUPPORT_LEGACY
489 scanlegacy =
490 #endif
491 scanpci = FALSE;
499 D(bug("[PCI-ATA] ata_Scan: Enumerating devices\n"));
501 if (scanpci)
504 * Attempt to get PCI subsytem object.
505 * If this fails, PCI isn't there. But it's not fatal for us.
507 OOP_Object *pci = OOP_NewObject(NULL, CLID_Hidd_PCI, NULL);
509 if (pci)
511 struct Hook FindHook =
513 .h_Entry = (IPTR (*)())ata_PCIEnumerator_h,
514 .h_Data = base
517 D(bug("[PCI-ATA] ata_Scan: Checking for supported PCI devices ..\n"));
520 * Obtain PCI attribute and method bases only once.
521 * We perform no result checks, because since PCI subsystem is in place,
522 * its attribute and method bases are also 100% in place.
524 if (!base->PCIDeviceAttrBase)
526 OOP_ObtainAttrBasesArray(&base->PCIDeviceAttrBase, &pciInterfaceIDs[ATTR_OFFSET]);
527 OOP_ObtainMethodBasesArray(&base->PCIMethodBase, pciInterfaceIDs);
530 HIDD_PCI_EnumDevices(pci, &FindHook, Requirements);
534 #ifdef SUPPORT_LEGACY
535 if (scanlegacy)
537 UBYTE n = base->legacycount;
539 D(bug("[PCI-ATA] ata_Scan: Adding Remaining Legacy-Buses\n"));
541 while (LegacyBuses[n].lb_Port)
543 probedbus = AllocVec(sizeof(struct ata_ProbedBus), MEMF_ANY);
544 if (probedbus)
546 probedbus->atapb_Node.ln_Name = (STRPTR)LegacyBuses[n].lb_Name;
547 probedbus->atapb_Node.ln_Type = ATABUSNODEPRI_LEGACY;
548 probedbus->atapb_Node.ln_Pri = ATABUSNODEPRI_LEGACY - (base->ata__buscount++);
549 probedbus->atapb_Device = NULL;
550 probedbus->atapb_Vendor = 0;
551 probedbus->atapb_Product = 0;
552 probedbus->atapb_BusNo = LegacyBuses[n].lb_Bus;
553 probedbus->atapb_IOBase = LegacyBuses[n].lb_Port;
554 probedbus->atapb_IOAlt = LegacyBuses[n].lb_Alt;
555 probedbus->atapb_INTLine = LegacyBuses[n].lb_IRQ;
556 probedbus->atapb_DMABase = 0;
558 D(bug("[PCI-ATA] ata_Scan: Adding Legacy Bus - IO: %x:%x\n",
559 probedbus->atapb_IOBase, probedbus->atapb_IOAlt));
561 Enqueue((struct List *)&base->probedbuses, &probedbus->atapb_Node);
563 n++;
566 #endif
568 D(bug("[PCI-ATA] ata_Scan: Registering Probed Buses..\n"));
570 HWBase = OOP_GetMethodID(IID_HW, 0);
571 while ((probedbus = (struct ata_ProbedBus *)RemHead((struct List *)&base->probedbuses)) != NULL)
573 struct TagItem attrs[] =
575 {aHidd_HardwareName , (IPTR)probedbus->atapb_Node.ln_Name},
576 {aHidd_Producer , probedbus->atapb_Vendor },
577 {aHidd_Product , probedbus->atapb_Product },
578 {aHidd_DriverData , (IPTR)probedbus },
579 {aHidd_ATABus_PIODataSize , sizeof(struct pio_data) },
580 {aHidd_ATABus_BusVectors , (IPTR)bus_FuncTable },
581 {aHidd_ATABus_PIOVectors , (IPTR)pio_FuncTable },
582 {aHidd_ATABus_DMADataSize , sizeof(struct dma_data) },
583 {aHidd_ATABus_DMAVectors , (IPTR)dma_FuncTable },
585 * Legacy ISA controllers have no other way to detect their
586 * presence. Do not confuse the user with phantom devices.
588 {aHidd_ATABus_KeepEmpty , probedbus->atapb_Node.ln_Type == ATABUSNODEPRI_LEGACY
589 ? FALSE : TRUE },
590 {TAG_DONE , 0 }
592 OOP_Object *bus;
595 * We use this field as ownership indicator.
596 * The trick is that HW_AddDriver() fails if either object creation fails
597 * or subsystem-side setup fails. In the latter case our object will be
598 * disposed.
599 * We need to know whether OOP_DisposeObject() or we should deallocate
600 * this structure on failure.
602 probedbus->atapb_Node.ln_Succ = NULL;
604 bus = HW_AddDriver(ata, base->busClass, attrs);
605 if (!bus)
607 D(bug("[PCI-ATA] Failed to create object for device %04X:%04X - IRQ %d, IO: %x:%x, DMA: %x\n",
608 probedbus->atapb_Vendor, probedbus->atapb_Product, probedbus->atapb_INTLine,
609 probedbus->atapb_IOBase, probedbus->atapb_IOAlt, probedbus->atapb_DMABase));
612 * Free the structure only upon object creation failure!
613 * In case of success it becomes owned by the driver object!
615 if (!probedbus->atapb_Node.ln_Succ)
617 DeviceUnref(probedbus->atapb_Device, base);
618 FreeVec(probedbus);
623 return TRUE;
626 ADD2INITLIB(ata_pci_Scan, 30)