Page 1 of 1

[ATA DMA Impl.] Disk controller not detected on PCI bus

Posted: Wed Aug 24, 2011 9:06 am
by fiveayem
Hi,

I have been developping an OS for two months now and today, I intend to implement ATA R/W via DMA. I have read the tutorial on the website, which is quite consistent. However, to configure DMA, I need to access the hard drive controller's PCI Configuration Space and my problem is this device is not detected on the PCI bus.

To be more precise, the only detected devices are the following (and there references do exist, cf. http://www.pcidatabase.com) :

Device 1 :
VendorID : 0x8086
DeviceID : 0x1237
Class code : 0x0006
Subclass : 0x0000

Device 2 :
VendorID : 0x8086
DeviceID : 0x7000
Class code : 0x0006
Subclass : 0x0001

Device 3 :
VendorID : 0x1013
DeviceID : 0x00B8
Class code : 0x0003
Subclass : 0x0000

Device 4 :
VendorID : 0x10EC
DeviceID : 0x8139
Class code : 0x0002
Subclass : 0x0000

Finally, you have here my code. I implemented PCI read/write functions in the same way as in Linux source code, that is to say that the functions belonging to PCIread.../PCIwrite... family work with the following parameters : bus, device, function, offset.

Code: Select all

void PCItest()
{
  u32 bus = 0, dev = 0;
  u16 vendorId = 0;
  while(bus < 2)
  {
    dev = 0;
    while(1)
    {
      vendorId = PCIreadWord(bus, dev, 0, PCI_REG_VENDOR_ID);
      if(vendorId != 0xFFFF)
      {
	print("Bus "); printnumber(bus); print(" device "); printnumber(dev); print("\n");
	print("   Vendor ID : "); printnumber(vendorId); print("\n");
	print("   Device ID : "); printnumber(PCIreadWord(bus, dev, 0, PCI_REG_DEVICE_ID)); print("\n");
	print("   Class code : "); printnumber(PCIreadByte(bus, dev, 0, PCI_REG_CLASS_CODE)); print("\n");
	print("   Subclass : "); printnumber(PCIreadByte(bus, dev, 0, PCI_REG_SUBCLASS)); print("\n");
	dev++;
      }
      else
	break;
    }
    bus++;
  }
}
Maybe this info may be of some help : I run my kernel on QEMU.

Thanks for your help.

PS : My code may be someway wrong. Indeed, it scans bus 0 and 1, but actually, I do not know if there can be more than one PCI bus in a machine.

PS 2 : Sorry if my English is not so good, I am French.

Re: [ATA DMA Impl.] Disk controller not detected on PCI bus

Posted: Wed Aug 24, 2011 9:14 am
by Combuster
It's not unlikely that the harddisk controller is on a multifunctional device, ie function is not 0. You should check function 0 if it has multiple functions to prevent getting duplicate results, and then enumerate functions 1..7 if it happens to be a multifunctional device.

Basically your current listing reads as northbridge, southbridge, pci slot 1 (vga), pci slot 2 (network). The southbridge usually has all the fun stuff to test your PCI detection algorithm, and in my local QEMU version, the primary ATA controller shows up as bus 0 device 1 function 1

Re: [ATA DMA Impl.] Disk controller not detected on PCI bus

Posted: Wed Aug 24, 2011 9:38 am
by fiveayem
Ok, and with function 1, can I access the device's PCI configuration space in the same way as function 0 ? Actually, why are some devices multifunctional ?

Re: [ATA DMA Impl.] Disk controller not detected on PCI bus

Posted: Wed Aug 24, 2011 9:47 am
by fiveayem
Thanks, it seems that works. So, if I have understood, for each bus and device, I have to "test" every function in order to gather a complete list of the devices connected to the buses, am I wright ?

Re: [ATA DMA Impl.] Disk controller not detected on PCI bus

Posted: Wed Aug 24, 2011 6:31 pm
by Bietje
fiveayem wrote:Thanks, it seems that works. So, if I have understood, for each bus and device, I have to "test" every function in order to gather a complete list of the devices connected to the buses, am I wright ?
Hi.

Almost right.. You should only check other functions of the devices if function 0 says its a multi function device. If you do not do this, several devices might show up 8 times (because they aren't multi function). So in pseudo code you should do something like:

Code: Select all

for(all busses)
{
  for(all devices)
  {
    for(all functions)
    {
      get vendor ID.. check it bla bla;

      if(function is not mf) break;
    }
  }
}
You didn't check all functions before. This is the reason you didn't found your IDE/SATA controller. On every PC I have tested so far was the IDE or SATA controller multi function.

So how do you check that magical multifunction feature thing? You start of with calculating the address specific to the current bus, devices and function:

Code: Select all

dword x = ((1 << 31) | (dev->bus << 16) | 
                (dev->device << 11) | (dev->func << 8) | ((reg & 0x3f) << 2)) & 
                (~3);
For the 'reg' variable you fill in 0x0C. This is the offset of the cache line size byte. On the dword of this offset are also the latency timer, the header type, and the BIST. We are only interested in the header type at this moment.

The layout of the header type is as follows:

Code: Select all

bit 7                  bits 6-0
multifunc              header type
So when you read a dword with offset 0xc you should shift it to the right by 16, this puts the start of the header type at bit 0 and then bitwise and the value with 0x80. If the result != 0, then you device is multi function.

I hope this helped you out,

Greets Bietje

Re: [ATA DMA Impl.] Disk controller not detected on PCI bus

Posted: Fri Aug 26, 2011 5:26 am
by fiveayem
Ok, thank you very much for your help ! :)