AHCI driver for RDOS

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

AHCI driver for RDOS

Post by rdos »

I've gathered the specification (AHCI is free, the SATA spec costed $25) and will start work on the AHCI using an asm-based device-driver. I've also located the source for Linux AHCI (unusable) and FreeBSD AHCI (a little more usable) in order to see how others have done.

I'll post progress here...
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

The SATA spec is over 750 pages, most of which is useless for driver-development. About the only usable information is the FIS-fields, and mostly the host-to-device FIS that is part of the AHCI interface.

The AHCI spec is only 123 pages, and more usable. The problem (as usual) is what functions to discard (the majority), and which must be implemented. The major issue is if it is possible to discard the ugly port multiplier functionality or not, and if anybody uses it, and for what in that case.

Each port can support up to 32 slots, but implementations are not required to support 32 slots. I suppose this would be about performance. If there are 32 non-continous outstanding requests for disc-IO, it would probably be best to queue them all for IO, and then wait for the completion of them all (but signalling owners as each request complete so owners can request new IO in parallel). I suspect that AHCI has a potential for much faster disc-IO than IDE, especially since my IDE driver uses PIO-mode.

The driver is here: http://rdos.net/vc/viewvc.cgi/trunk/ker ... iew=markup
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

Part of the problem of optimizing is how many slots to use, and how many scatter-gather entries to support. Hardware sets a limit of 32 slots, but as little as one may be implemented. My current design will setup 32 slots with a maximum of 20 scatter.gather entries. Ordinary sectors are 512 bytes, and each scatter-gather entry is best represented as a single sector (because then the sector handle can be put in the reserved space of the scatter-gather entry).

I think there is a need for static command-lists and command-tables, meaning that number of slots and scatter-gather entries cannot change. The current lists would require 5 physical pages (20k) per AHCI port, which should be ok.

The alternative would be to allocate command-tables dynamically, but I doubt this would have a performance benefit, rather it would waste CPU cycles instead.

What I still might consider is to construct an algorithm that can adapt to different number of slots, and increase number of scatter-gather entries as number of slots decrease to always use the memory available. This might be a table with 32-entries in the code-segment.

I'll have a 32-entry table for command list and command table offsets so I can get to a list/table fast regardless of table sizes which change based on scatter-gather entry counts. It is not possible to statically allocate these things in structures (using C wouldn't help much either).
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

A table of 32 slot-number entries that have:
1. # of slots to use
2. # of scatter-gather entries to use
3. size of PRD-table
4. # of physical pages required

Code: Select all

prd_slot_table  STRUC

prd_slots       DW ?
prd_entries     DW ?
prd_size        DW ?
prd_pages       DW ?

prd_slot_table  ENDS

p1   prd_slot_table <1, 1F8h, 2000h, 2>
p2   prd_slot_table <2, 0F8h, 1000h, 2>
p3   prd_slot_table <3, 0A0h, 0A80h, 2>
p4   prd_slot_table <4, 78h, 800h, 2>
p5   prd_slot_table <5, 90h, 980h, 3>
p6   prd_slot_table <6, 78h, 800h, 3>
p7   prd_slot_table <7, 88h, 900h, 4>
p8   prd_slot_table <8, 78h, 800h, 4>
p9   prd_slot_table <9, 68h, 700h, 4>
p10  prd_slot_table <10, 58h, 600h, 4>
p11  prd_slot_table <11, 50h, 580h, 4>
p12  prd_slot_table <12, 48h, 500h, 4>
p13  prd_slot_table <12, 48h, 500h, 4>
p14  prd_slot_table <14, 40h, 480h, 4>
p15  prd_slot_table <14, 40h, 480h, 4>
p16  prd_slot_table <16, 38h, 400h, 4>
p17  prd_slot_table <16, 38h, 400h, 4>
p18  prd_slot_table <18, 30h, 380h, 4>
p19  prd_slot_table <18, 30h, 380h, 4>
p20  prd_slot_table <18, 30h, 380h, 4>
p21  prd_slot_table <21, 28h, 300h, 4>
p22  prd_slot_table <21, 28h, 300h, 4>
p23  prd_slot_table <21, 28h, 300h, 4>
p24  prd_slot_table <21, 28h, 300h, 4>
p25  prd_slot_table <25, 20h, 280h, 4>
p26  prd_slot_table <25, 20h, 280h, 4>
p27  prd_slot_table <25, 20h, 280h, 4>
p28  prd_slot_table <25, 20h, 280h, 4>
p29  prd_slot_table <25, 20h, 280h, 4>
p30  prd_slot_table <25, 20h, 280h, 4>
p31  prd_slot_table <25, 20h, 280h, 4>
p32  prd_slot_table <32, 20h, 280h, 5>
Makes this a snap. I require at least 32 scatter-gather entries at the high-end side, and decrease number of physical pages when more than 128 scatter-gather entries could be fitted down to 2 physical pages.

With this table, 32 slots will use 32 scatter-gather entries, and use 5 physical pages. Between 5 and 31 slots will use 4 physical pages. If only one slot is available, it would use 2 physical pages, and support 504 scatter-gather entries. One additional physical page is used for misc. port data. If FIS based switching is used, this requires another physical page.

Status update: All the tables are initialized. The devices are RESETED, and the power-up logic seems to work up to starting both the FIS receiver and the command engine. Next is to try to read-out the drive configuration.
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

I figured out I need a few operational procedures now:

1. Allocate a slot (this is done by finding a clear bit in port x command issue)
2. Find the command table address
3. Fill in the FIS with the sector & command code for ATA
4. Add the data buffers to the PRDT (and notice the maximum number of entries as described in the above table).
5. Find and update the command list entry
6. Set the allocated slot-bit so the AHCI controller issues the command
7. Wait for command completion

The first command I need to issue is the IDENTIFY DEVICE (0xEC), as this would return vital drive-information.
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

There seems to be some type of fatal problem with the in-memory tables, because the controller encounters non-recoverable errors on one disc, and return "command not supported" on the other + strange LBA values.

I suppose I need to create shadow-tables from the physical addresses in order to see what the command table actually looks like to hardware.

Update: Turns out that it does work if single-stepped. There is some kind of race-condition in the initialization code. Anyway, now I got the identification sector from the ATA drive with the correct number of (48-bit LBA) sectors, and an error from the CD/DVD drive.
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

More problems. I cannot make the IRQ for AHCI fire, and I suspect the chipset is using MSI signalling. The PCI specification is required in order to understand MSI, but the document is only available to PCI-sig members, and membership costs $3000 (out of the question). However, search engines was my friend, and the specification is available for download. :mrgreen:

What I still don't understand is what address MSI would write to, and what data. Perhaps the x86-processor documents would describe this?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: AHCI driver for RDOS

Post by Brendan »

Hi,
rdos wrote:What I still don't understand is what address MSI would write to, and what data. Perhaps the x86-processor documents would describe this?
Which address MSI writes to and what data it should write is determined by the architecture (e.g. 80x86 may be completely different to ARM, and both may be completely different to PowerPC, etc). PCISIG only control "how" it's sent from devices to the chipset and not "where and what" the chipset expects, and so it won't be part of PCI standards.

For 80x86, which address MSI writes to and what data it should write is detailed in Intel's manuals (e.g. "10.11 MESSAGE SIGNALLED INTERRUPTS" within the "APIC" chapter of the System Programming Guide). Alternatively, you can find information on MSI in the datasheets for various Intel chipsets that support it.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

Brendan wrote:Which address MSI writes to and what data it should write is determined by the architecture (e.g. 80x86 may be completely different to ARM, and both may be completely different to PowerPC, etc). PCISIG only control "how" it's sent from devices to the chipset and not "where and what" the chipset expects, and so it won't be part of PCI standards.

For 80x86, which address MSI writes to and what data it should write is detailed in Intel's manuals (e.g. "10.11 MESSAGE SIGNALLED INTERRUPTS" within the "APIC" chapter of the System Programming Guide). Alternatively, you can find information on MSI in the datasheets for various Intel chipsets that support it.
OK, found it. IOW, MSI seems to be done in a similar way as when the IO-APIC signals interrupts, only it goes directly to the core instead of via IO-APIC. It seems like AMD does not document MSI, but everything points in the direction that it works the same way, with the same address and data encodings. How it works on ARM or PowerPC is of no interest to me. :mrgreen:

I've added 64 vectors for MSI (0A0h - 0DFh) which can be allocated in sizes of a power of two (1,2,4,8,16 or 32 vectors). I have an allocation function for vectors, and then a function that sets up the int-handler per vector. The stubs for MSI interrupts is basically identical to the stubs for ordinary APIC-ints (the EOI is done to the APIC).

I also need to add the capability-interface to PCI in order to find the MSI capability function number(s).

In the AHCI-driver, there would be two primary modes of operation. Either the device asks for one vector, and then that vector would handle all ports, or the device asks for multiple vectors, and if those can be allocated, there will be one vector per port. I won't bother with the half-baked solution of sharing the last vector. Of course, one vector per port is the most effective, especially for multi-core computers since the IRQs can then run in parallell (I'll use lowest priority delivery-mode) and I don't need to decode port-ISR bits.
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

Still no luck with IRQs from AHCI. I've found out that the AHCI HBA has a MSI-capability, but it is not enabled. Additionally, it does not have a MSI-X capability. This should mean that it would use PCI IRQs, and not MSI. I'm pretty sure that I've used the correct IRQ, as I put a fixed value of IRQ 19 that Windows reports rather than relying on my own IRQ-identication which is not yet updated to use ACPI.

Some other observations:
1. MC.MSIE is not enabled (PCI IRQs is used)
2. GHC.IE is set (global interrupt flag is set)
3. CMD.ID is clear (interrupts are not disabled in PCI)
4. There are no pending interrupts in the PCI device-status
5. The IS bits for both implemented ports are set in the AHCI device (both ports request interrupts)
6. In the ATA port, the PRD completed bit is set in PxIS, and this interrupt is also enabled in PxIE
7. In the ATAPI port, no bit is set in PxIS
8. In the IOAPIC, interrupts are set as edge-triggered, and the MSI function also set edge-triggered mode.

The PCI IRQ is never called, and when forcing MSI-function, no interrupt is generated from the device either. I really wonder what could be wrong. :evil:
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

It still doesn't work, but now I can at least confirm that PCI has asserted the IRQ when running in PCI IRQ-mode. I missed this before since I read the wrong PCI-registers. When running in MSI-mode, the bit is not set.

PCI configuration space registers:

Code: Select all

CMD:   0007
BME
MSE
ISOE

STS:   02B8  
STS:   0000 0010 1011 1000
FBC
C66
CL
IS

INTR:  0205
Pin    2
Line   5
Global HBA registers:

Code: Select all

CAP:   E720FFC3
CAP: 1110 0111 0010 0000 1111 1111 1100 0011
S64A
SNCQ
SSNTF
SALP
SAL
SCLO
Gen 2
PMD
SSC
PSC
NCS=32
CCCS
EMS
Ports=3

GHC:   80000002
GHC: 1000 0000 0000 0000 0000 0000 0000 0010
AE
IE

IS:    00000001
PI:    00000003
VS:    00010200

C_CTL: 00010130
C_CTL: 0000 0000 0000 0001 0000 0001 0011 0000
Timeout = 1ms
CC = 1
Int=6

C_PORT:00000000
E_LOC: 01000002
EM_CTL:07010000
CAP2:  00000000
BOHC:  00000000
Port 1 HBA registers (ATA)

Code: Select all

PxCLB: 00000000003DA800
PxFB:  00000000003DA700
PxIS:  00000022
PxIS:  0000 0000 0000 0000 0000 0000 0010 0010
DPS
PSS

PxIE:  79400060

PxCMD: 0000C017
PxCMD: 0000 0000 0000 0000 1100 0000 0001 0111
CR
FR
FRE
POD
SUD
ST

PxTFD: 00000050
PxSIG: 00000101
LBA: 1
Count: 1

PxSSTS:00000113
PxSSTS: 0000 0000 0000 0000 0000 0001 0001 0011
Active
Gen 1
Present

PxSCTL:00000000
PxSERR:00000000
PxSACT:00000000
PxCI:  00000000
PxSNTF:00000000
PxFBS: 00000000
Port 2 HBA registers (ATAPI):

Code: Select all

PxCLB: 00000000003E0800
PxFB:  00000000003E0700
PxIS:  00000000
PxIE:  79400060
PxCMD: 0000C017
PxTFD: 00000100
PxTFD: 0000 0000 0000 0000 0000 0001 0000 0000
ERR

PxSIG: EB140101
LBA: EB1401
Count: 1

PxSSTS:00000113
PxSSTS: 0000 0000 0000 0000 0000 0001 0001 0011
Active
Gen 1
Present

PxSCTL:00000000
PxSERR:00000000
PxSACT:00000000
PxCI:  00000000
PxSNTF:00000000
PxFBS: 00000000
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

I've now tested all free vectors in IO-APIC in conjunction with PCI IRQs, and none of them seem to get called. I suspect that the PCI-line is not routed to the APIC.

That leaves MSI as the only option.

Here are the MSI settings:

Code: Select all

80: 
Cap:  05

81:
Next: 70

82:
Msi control: 0049
0000 0000 0100 1001
16 vectors enable
16 vectors cap
MSIE

84:
Address: FEEFF00C
FEE: bit 20-31 according to Intel
Dest: FF
RH: 1 (lowest prio)
DM: 1 (logical)

88:
Data: 01A0
0000 0001 1010 0000
Edge mode
Lowest prio
Vector: A0
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

By setting RH=DM=0 it works. :D :D

Now I have a functioning IRQ and I can continue where I left off with driver.

Edit: With this code the IDENTIFY command is race-free and can be run at full speed with no problems. Next would be to read the partition table.
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

Now the first step in the file-system initialization process works (the disc assign callback). The next two steps (drive assign 1&2) would be next.
rdos
Member
Member
Posts: 3308
Joined: Wed Oct 01, 2008 1:55 pm

Re: AHCI driver for RDOS

Post by rdos »

Now read sector also works, and both drive-assign callbacks work. Now only the actual sector read/write server-thread needs to be implemented.
Post Reply