Page 1 of 1

SATA I/O Ports

Posted: Mon Oct 31, 2011 11:53 am
by IanSeyler
I recall reading a while back that a SATA harddrive could be accessed via legacy ports just like IDE drives. Is this true? If so is there information on the configuration?

Currently I have an IDE (PATA) driver in assembly that works well but would like to create a SATA driver as well.

Mainly something like this but for SATA:

Code: Select all

; -----------------------------------------------------------------------------
; readsectors -- Read sectors on the hard drive
; IN:	RAX = starting sector to read
;	RCX = number of sectors to read (1 - 256)
;	RDI = memory location to store sectors
; OUT:	RAX = RAX + number of sectors that were read
;	RCX = number of sectors that were read (0 on error)
;	RDI = RDI + (number of sectors * 512)
;	All other registers preserved
readsectors:
	push rdx
	push rcx
	push rbx
	push rax

	push rcx		; Save RCX for use in the read loop
	mov rbx, rcx		; Store number of sectors to read
	cmp rcx, 256
	jg readsectors_fail	; Over 256? Fail!
	jne readsectors_skip	; Not 256? No need to modify CL
	xor rcx, rcx		; 0 translates to 256
readsectors_skip:

	push rax		; Save RAX since we are about to overwrite it
	mov dx, 0x01F2		; 0x01F2 - Sector count Port 7:0
	mov al, cl		; Read CL sectors
	out dx, al
	pop rax			; Restore RAX which is our sector number
	inc dx			; 0x01F3 - LBA Low Port 7:0
	out dx, al
	inc dx			; 0x01F4 - LBA Mid Port 15:8
	shr rax, 8
	out dx, al
	inc dx			; 0x01F5 - LBA High Port 23:16
	shr rax, 8
	out dx, al
	inc dx			; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24)
	shr rax, 8
	and al, 00001111b 	; Clear bits 4-7 just to be safe
	or al, 01000000b	; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master)
	out dx, al
	inc dx			; 0x01F7 - Command Port
	mov al, 0x20		; Read sector(s). 0x24 if LBA48
	out dx, al

	mov rcx, 4
readsectors_wait:
	in al, dx		; Read status from 0x01F7
	test al, 0x80		; BSY flag set?
	jne readsectors_retry
	test al, 0x08		; DRQ set?
	jne readsectors_dataready
readsectors_retry:
	dec rcx
	jg readsectors_wait
readsectors_nextsector:
	in al, dx		; Read status from 0x01F7
	test al, 0x80		; BSY flag set?
	jne readsectors_nextsector
	test al, 0x21		; ERR or DF set?
	jne readsectors_fail

readsectors_dataready:
	sub dx, 7		; Data port (0x1F0)
	mov rcx, 256		; Read 
	rep insw		; Copy a 512 byte sector to RDI
	add dx, 7		; Set DX back to status register (0x01F7)
	in al, dx		; Delay ~400ns to allow drive to set new values of BSY and DRQ
	in al, dx
	in al, dx
	in al, dx

	dec rbx			; RBX is the "sectors to read" counter
	cmp rbx, 0
	jne readsectors_nextsector

	pop rcx
	pop rax
	pop rbx
	add rax, rcx
	pop rcx
	pop rdx
ret

readsectors_fail:
	pop rcx
	pop rax
	pop rbx
	pop rcx
	pop rdx
	xor rcx, rcx		; Set RCX to 0 since nothing was read
ret
; -----------------------------------------------------------------------------
Thanks,
Ian

Re: SATA I/O Ports

Posted: Mon Oct 31, 2011 12:58 pm
by Brynet-Inc
When a SATA controller shows up as a PCI IDE controller it's typically in native-mode, not compatible-mode.. I believe this means legacy I/O port accesses are not translated by the chipset.

So you'll at least need to write a PCI IDE driver, note however, that you'll also need to deal with systems that configure the device for AHCI mode by default.. which could mean writing an AHCI driver or adding some device quirks for PCI IDE mode.

Honestly it depends on the BIOS, in the best case, it might set up legacy translation.. or it might just do the bare minimum and fiddle with the devices PCI configuration registers, like the class code.

Re: SATA I/O Ports

Posted: Mon Oct 31, 2011 1:28 pm
by rdos
What you currently have is an IDE driver that uses PIO-mode (just like I have). It's not really very fast, nor would it be supported on a lot of new hardware.

The next step is to write a PCI IDE driver. What you need in order to do that is to implement PCI, and then use your PCI interface to get the IO-base addresses of the PCI IDE drives installed in the system. Then you would use those addresses just like you do now, only with different addresses. It didn't take me long to extend my IDE driver with PCI-support (but I already had the PCI functionality at that time).

The next logical step is to write an AHCI-driver, which is a whole lot more complex than a PIO IDE driver. OTOH, an AHCI driver is much faster than a IDE PIO-mode driver, so it might very well be worth the effort + compability-mode would cease to exist as most major OSes come with AHCI-drivers. AHCI also solve the current size-limits of the IDE interface, so as drives start to get bigger than those limits, IDE would quite likely disappear.

Re: SATA I/O Ports

Posted: Tue Nov 01, 2011 1:24 am
by egos
Both you are right. But why you didn't tell about PCI IDE driver with DMA support. It's really full complete driver for PCI IDE. It uses BM register set as well.

Re: SATA I/O Ports

Posted: Tue Nov 01, 2011 1:39 am
by rdos
egos wrote:Both you are right. But why you didn't tell about PCI IDE driver with DMA support. It's really full complete driver for PCI IDE. It uses BM register set as well.
It is possible to write a PCI IDE driver with DMA-support, but this solution would still not out-perform an AHCI solution since AHCI has a dedicated busmaster that talks to the device. With AHCI, you simply add requests in memory, and basically don't need to handle the device directly unless something goes wrong, which is signalled with interrupts. IOW, there are no drive status polls and similar.

Re: SATA I/O Ports

Posted: Tue Nov 01, 2011 12:44 pm
by Brynet-Inc
I didn't suggest the OP should only implement PIO, adding support for DMA/UDMA modes is a no-brainer.