ahci reading
This commit is contained in:
parent
05eab23956
commit
babe4290e4
@ -463,9 +463,9 @@ begin
|
|||||||
cmd := cmd or PCI_COMMAND_BUS_MASTER;
|
cmd := cmd or PCI_COMMAND_BUS_MASTER;
|
||||||
cmd := cmd or (3 shl 1);
|
cmd := cmd or (3 shl 1);
|
||||||
|
|
||||||
//enable interrupts, remove disable interrupt bit
|
//enable interrupts, remove disable interrupt bit maybe
|
||||||
cmd := cmd and not PCI_COMMAND_INT_DISABLE;
|
cmd := cmd and not PCI_COMMAND_INT_DISABLE;
|
||||||
cmd := cmd and not (1 shl 9);
|
// cmd := cmd and not (1 shl 9);
|
||||||
|
|
||||||
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
||||||
outl(PCI_CONFIG_DATA_PORT, cmd);
|
outl(PCI_CONFIG_DATA_PORT, cmd);
|
||||||
|
@ -38,6 +38,12 @@ const
|
|||||||
PCI_COMMAND_INT_DISABLE = $0400;
|
PCI_COMMAND_INT_DISABLE = $0400;
|
||||||
PCI_COMMAND_SERR_ENABLE = $8000;
|
PCI_COMMAND_SERR_ENABLE = $8000;
|
||||||
|
|
||||||
|
PCI_CAP_ID_MSI = $05;
|
||||||
|
|
||||||
|
// Bits in the MSI Control register (16-bit):
|
||||||
|
MSI_CONTROL_ENABLE = 1 shl 0; // Bit 0
|
||||||
|
MSI_CONTROL_64BIT = 1 shl 7; // Bit 7
|
||||||
|
MSI_CONTROL_PVMASK = 1 shl 8; // Bit 8 (optional: per-vector masking)
|
||||||
type
|
type
|
||||||
|
|
||||||
PPCI_Device = ^TPCI_Device;
|
PPCI_Device = ^TPCI_Device;
|
||||||
|
@ -42,8 +42,13 @@ var
|
|||||||
procedure init();
|
procedure init();
|
||||||
function load(ptr : void) : boolean;
|
function load(ptr : void) : boolean;
|
||||||
procedure check_ports(controller : PAHCI_Controller);
|
procedure check_ports(controller : PAHCI_Controller);
|
||||||
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32);
|
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32; isATAPI : boolean);
|
||||||
procedure ahci_isr();
|
procedure ahci_isr();
|
||||||
|
function find_cmd_slot(device : PAHCI_Device) : uint32;
|
||||||
|
function send_read_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
// function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
function read_atapi(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@ -142,7 +147,7 @@ begin
|
|||||||
console.writestring(' implemented on controller ');
|
console.writestring(' implemented on controller ');
|
||||||
console.writehexln(uint32(controller^.pci_device^.address5));
|
console.writehexln(uint32(controller^.pci_device^.address5));
|
||||||
|
|
||||||
device := PAHCI_Device(DL_Add(controller^.devices));
|
device := PAHCI_Device(@controller^.devices[i]);
|
||||||
device^.port := port;
|
device^.port := port;
|
||||||
|
|
||||||
//check if the port is active TODO
|
//check if the port is active TODO
|
||||||
@ -230,9 +235,13 @@ begin
|
|||||||
console.writestring('AHCI: sata status: ');
|
console.writestring('AHCI: sata status: ');
|
||||||
console.writehexln(port^.sata_status);
|
console.writehexln(port^.sata_status);
|
||||||
|
|
||||||
//pass devices count as second param
|
// //pass devices count as second param
|
||||||
if (device^.device_type = SATA) then begin
|
if (device^.device_type = SATA) then begin
|
||||||
identify_device(controller, DL_Size(controller^.devices) - 1);
|
identify_device(controller, i, false);
|
||||||
|
end else if (device^.device_type = ATAPI) then begin
|
||||||
|
identify_device(controller, i, true);
|
||||||
|
end else begin
|
||||||
|
console.writestringln('AHCI: Unsupported device type');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
controller^.mio^.int_status := $FFFFFFFF;
|
controller^.mio^.int_status := $FFFFFFFF;
|
||||||
@ -242,7 +251,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32);
|
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32; isATAPI : boolean);
|
||||||
var
|
var
|
||||||
fis : PHBA_FIS_REG_H2D;
|
fis : PHBA_FIS_REG_H2D;
|
||||||
cmd_header : PHBA_CMD_HEADER;
|
cmd_header : PHBA_CMD_HEADER;
|
||||||
@ -255,18 +264,23 @@ var
|
|||||||
sec_count : uint32;
|
sec_count : uint32;
|
||||||
b8 : puint16;
|
b8 : puint16;
|
||||||
begin
|
begin
|
||||||
console.writestringln('AHCI: Identifying device');
|
console.writestring('AHCI: Identifying device ');
|
||||||
device := PAHCI_Device(DL_Get(controller^.devices, portIndex));
|
console.writeintln(portIndex);
|
||||||
|
device := PAHCI_Device(@controller^.devices[portIndex]);
|
||||||
|
|
||||||
// (Optional) Print the device type if you store it:
|
// (Optional) Print the device type if you store it:
|
||||||
console.writestring('AHCI: Device type: ');
|
console.writestring('AHCI: Device type: ');
|
||||||
// For example: if device^.device_type = SATA then ...
|
// For example: if device^.device_type = SATA then ...
|
||||||
console.writestring('AHCI: sata status: ');
|
console.writestring('AHCI: sata status: ');
|
||||||
console.writehexln(device^.port^.sata_status);
|
console.writehexln(device^.port^.sata_status);
|
||||||
|
console.writestring('AHCI: signature: ');
|
||||||
|
console.writehexln(device^.port^.signature);
|
||||||
|
console.writestring('AHCI: device type: ');
|
||||||
|
console.writeintln(uint32(device^.device_type));
|
||||||
|
|
||||||
//clear any pending interrupts
|
//clear any pending interrupts
|
||||||
device^.port^.int_status := $FFFFFFFF;
|
device^.port^.int_status := $0;
|
||||||
device^.port^.int_enable := 0;
|
device^.port^.int_enable := $FFFFFFFF;
|
||||||
|
|
||||||
// Allocate a 512-byte DMA buffer for the IDENTIFY data
|
// Allocate a 512-byte DMA buffer for the IDENTIFY data
|
||||||
buffer := kalloc(512);
|
buffer := kalloc(512);
|
||||||
@ -279,6 +293,9 @@ begin
|
|||||||
cmd_header^.wrt := 0;
|
cmd_header^.wrt := 0;
|
||||||
cmd_header^.prdtl := 1;
|
cmd_header^.prdtl := 1;
|
||||||
cmd_header^.clear_busy := 1;
|
cmd_header^.clear_busy := 1;
|
||||||
|
if isATAPI then begin
|
||||||
|
cmd_header^.atapi := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
// Setup the command table (using slot 0)
|
// Setup the command table (using slot 0)
|
||||||
@ -287,18 +304,27 @@ begin
|
|||||||
cmd_table^.prdt[0].dbc := 511; // 512 bytes (0-based count)
|
cmd_table^.prdt[0].dbc := 511; // 512 bytes (0-based count)
|
||||||
cmd_table^.prdt[0].int := 1; // Interrupt on completion
|
cmd_table^.prdt[0].int := 1; // Interrupt on completion
|
||||||
|
|
||||||
|
if isATAPI then begin
|
||||||
|
// ATAPI Identify Device command
|
||||||
|
buffer[0] := $A1; // ATAPI Identify Device
|
||||||
|
end;
|
||||||
|
|
||||||
// Construct the Command FIS in the command table's CFIS area
|
// Construct the Command FIS in the command table's CFIS area
|
||||||
fis := PHBA_FIS_REG_H2D(@device^.command_table^.cmd_fis);
|
fis := PHBA_FIS_REG_H2D(@device^.command_table^.cmd_fis);
|
||||||
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||||
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||||
fis^.c := $1;
|
fis^.c := $1;
|
||||||
|
if isATAPI then begin
|
||||||
|
fis^.command := ATA_CMD_IDENTIFY_PACKET;
|
||||||
|
end else begin
|
||||||
fis^.command := ATA_CMD_IDENTIFY;
|
fis^.command := ATA_CMD_IDENTIFY;
|
||||||
|
end;
|
||||||
fis^.device := $A0; // LBA mode 40?
|
fis^.device := $A0; // LBA mode 40?
|
||||||
|
|
||||||
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||||
while (device^.port^.tfd and $88) <> 0 do begin
|
while (device^.port^.tfd and $88) <> 0 do begin
|
||||||
console.writestring('AHCI: tfd: ');
|
// console.writestring('AHCI: tfd: ');
|
||||||
console.writehexln(device^.port^.tfd);
|
// console.writehexln(device^.port^.tfd);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Issue the command by setting bit 0 in the port's Command Issue register.
|
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||||
@ -356,6 +382,25 @@ begin
|
|||||||
|
|
||||||
|
|
||||||
console.writestringln('');
|
console.writestringln('');
|
||||||
|
|
||||||
|
buffer := puint32(kalloc(512));
|
||||||
|
memset(uint32(buffer), 0, 512);
|
||||||
|
|
||||||
|
//send a read DMA command to the device
|
||||||
|
if isATAPI then begin
|
||||||
|
read_atapi(device, 16, 512, buffer);
|
||||||
|
end else begin
|
||||||
|
send_read_dma(device, 10, 512, buffer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
//print the buffer
|
||||||
|
for i:=0 to 63 do begin
|
||||||
|
console.writehex(uint32(buffer[i]));
|
||||||
|
console.writestring(' ');
|
||||||
|
end;
|
||||||
|
console.writestringln('');
|
||||||
|
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -382,7 +427,8 @@ begin
|
|||||||
device := PPCI_Device(ptr);
|
device := PPCI_Device(ptr);
|
||||||
|
|
||||||
pci.enableDevice(device^.bus, device^.slot, device^.func);
|
pci.enableDevice(device^.bus, device^.slot, device^.func);
|
||||||
int_no := device^.interrupt_line;
|
psleep(5);
|
||||||
|
int_no := device^.interrupt_line + 32;
|
||||||
|
|
||||||
|
|
||||||
//print interrupt number
|
//print interrupt number
|
||||||
@ -390,7 +436,6 @@ begin
|
|||||||
console.writehexln(int_no);
|
console.writehexln(int_no);
|
||||||
|
|
||||||
controller := PAHCI_Controller(DL_Add(ahciControllers));
|
controller := PAHCI_Controller(DL_Add(ahciControllers));
|
||||||
controller^.devices := DL_New(SizeOf(TAHCI_Device));
|
|
||||||
|
|
||||||
controller^.pci_device := PPCI_Device(device);
|
controller^.pci_device := PPCI_Device(device);
|
||||||
|
|
||||||
@ -439,40 +484,381 @@ begin
|
|||||||
while (base^.global_ctrl and 1) <> 0 do begin
|
while (base^.global_ctrl and 1) <> 0 do begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
registerISR(int_no, @ahci_isr);
|
registerISR(int_no, @ahci_isr);
|
||||||
|
|
||||||
//enable AHCI mode, TODO check if is not already in AHCI mode and enable it, also perhaps remove if loaded as IDE
|
//enable AHCI mode, TODO check if is not already in AHCI mode and enable it, also perhaps remove if loaded as IDE
|
||||||
base^.global_ctrl := base^.global_ctrl or AHCI_CONTROLLER_MODE;
|
base^.global_ctrl := base^.global_ctrl or AHCI_CONTROLLER_MODE;
|
||||||
base^.global_ctrl := base^.global_ctrl or $2; //enable interrupts
|
// base^.global_ctrl := base^.global_ctrl or $2; //enable interrupts
|
||||||
|
|
||||||
|
//disable interrupts
|
||||||
|
base^.global_ctrl := base^.global_ctrl or $2;
|
||||||
|
|
||||||
//clear any pending interrupts
|
//clear any pending interrupts
|
||||||
base^.int_status := $FFFFFFFF;
|
base^.int_status := $FFFFFFFF;
|
||||||
|
|
||||||
check_ports(controller);
|
check_ports(controller);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// console.writestringln('AHCI: initilizing a new controller');
|
|
||||||
// ahciControllers[ahciControllerCount] := ptr;
|
|
||||||
// hba[ahciControllerCount] := PPCI_Device(ptr)^.address5;
|
|
||||||
// new_page_at_address(hba[ahciControllerCount]);
|
|
||||||
|
|
||||||
// //here would be any controller setup needed
|
|
||||||
|
|
||||||
// check_ports(ahciControllerCount);
|
|
||||||
// ahciControllerCount += 1;
|
|
||||||
// exit(true);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure ahci_isr();
|
procedure ahci_isr();
|
||||||
begin
|
begin
|
||||||
console.writestringln('AHCI: ISR');
|
console.writestringln('AHCI: ISR');
|
||||||
|
console.redrawWindows();
|
||||||
//welp there is no way to know what port caused the interrupt or even if it was the controller
|
//welp there is no way to know what port caused the interrupt or even if it was the controller
|
||||||
//so we will just have to check all ports, and figure the operation that caused the interrupt
|
//so we will just have to check all ports, and figure the operation that caused the interrupt
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function find_cmd_slot(device : PAHCI_Device) : uint32;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
begin
|
||||||
|
// for i:=0 to 31 do begin
|
||||||
|
// if (device^.port^.cmd_issue[i] and $80000000) = 0 then begin
|
||||||
|
// exit(i);
|
||||||
|
// end;
|
||||||
|
// end;
|
||||||
|
exit(0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function send_read_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
var
|
||||||
|
fis : PHBA_FIS_REG_H2D;
|
||||||
|
cmd_header : PHBA_CMD_HEADER;
|
||||||
|
cmd_table : PHBA_CMD_TABLE;
|
||||||
|
cmd : uint32;
|
||||||
|
i, timeout : uint32;
|
||||||
|
tfd : uint32;
|
||||||
|
sec_count : uint32;
|
||||||
|
prdt_count : uint32;
|
||||||
|
b8 : puint16;
|
||||||
|
slot : uint32;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: Sending read DMA command');
|
||||||
|
|
||||||
|
reset_port(device^.port);
|
||||||
|
start_port(device^.port);
|
||||||
|
|
||||||
|
//prdt count is 22 bits
|
||||||
|
prdt_count := (count div 4194304) + 1;
|
||||||
|
|
||||||
|
if prdt_count > 32 then begin
|
||||||
|
send_read_dma := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use command slot 0 for the IDENTIFY command.
|
||||||
|
slot := find_cmd_slot(device);
|
||||||
|
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
|
||||||
|
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
|
||||||
|
cmd_header^.wrt := 0;
|
||||||
|
cmd_header^.prdtl := prdt_count;
|
||||||
|
cmd_header^.clear_busy := 1;
|
||||||
|
|
||||||
|
// Setup the command table (using slot 0)
|
||||||
|
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
|
||||||
|
|
||||||
|
for i:=0 to prdt_count - 1 do begin
|
||||||
|
cmd_table^.prdt[i].dba := vtop(uint32(buffer) + (i * 4194304));
|
||||||
|
|
||||||
|
if i = prdt_count - 1 then begin
|
||||||
|
cmd_table^.prdt[i].dbc := count - (i * 4194304) - 1; // 512 bytes (0-based count)
|
||||||
|
end else begin
|
||||||
|
cmd_table^.prdt[i].dbc := 4194304 - 1; // 512 bytes (0-based count)
|
||||||
|
end;
|
||||||
|
|
||||||
|
cmd_table^.prdt[i].int := 1; // Interrupt on completion
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Construct the Command FIS in the command table's CFIS area
|
||||||
|
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
|
||||||
|
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||||
|
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||||
|
fis^.c := $1;
|
||||||
|
fis^.command := ATA_CMD_READ_DMA_EXT;
|
||||||
|
fis^.device := $40; // LBA mode 48?
|
||||||
|
|
||||||
|
fis^.lba0 := lba and $FF;
|
||||||
|
fis^.lba1 := (lba shr 8) and $FF;
|
||||||
|
fis^.lba2 := (lba shr 16) and $FF;
|
||||||
|
fis^.lba3 := (lba shr 24) and $FF;
|
||||||
|
fis^.lba4 := (lba shr 32) and $FF;
|
||||||
|
|
||||||
|
fis^.countl := count and $FF;
|
||||||
|
fis^.counth := (count shr 8) and $FF;
|
||||||
|
|
||||||
|
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||||
|
while (device^.port^.tfd and $88) <> 0 do begin
|
||||||
|
// console.writestring('AHCI: tfd: ');
|
||||||
|
// console.writehexln(device^.port^.tfd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||||
|
cmd := device^.port^.cmd_issue;
|
||||||
|
cmd := cmd or (1 shl slot);
|
||||||
|
device^.port^.cmd_issue := cmd;
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Sent read DMA command');
|
||||||
|
|
||||||
|
// Wait for command completion with a timeout.
|
||||||
|
timeout := 0;
|
||||||
|
repeat
|
||||||
|
cmd := device^.port^.cmd_issue; // Command Issue register
|
||||||
|
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
|
||||||
|
timeout := timeout + 10;
|
||||||
|
if timeout > 100000 then begin
|
||||||
|
console.writestringln('AHCI: Read DMA command timeout');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
// check for bit 30 in the tfd register
|
||||||
|
if (tfd and $40000000) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: error');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Command complete');
|
||||||
|
|
||||||
|
// Check for an error flag in the command register (bit 1)
|
||||||
|
if (cmd and (1 shl slot)) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: Error sending read DMA command');
|
||||||
|
|
||||||
|
// Check the error register for more information
|
||||||
|
console.writestring('AHCI: Error register: ');
|
||||||
|
console.writehexln(device^.port^.sata_error);
|
||||||
|
end;
|
||||||
|
|
||||||
|
send_read_dma := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
var
|
||||||
|
fis : PHBA_FIS_REG_H2D;
|
||||||
|
cmd_header : PHBA_CMD_HEADER;
|
||||||
|
cmd_table : PHBA_CMD_TABLE;
|
||||||
|
cmd : uint32;
|
||||||
|
i, timeout : uint32;
|
||||||
|
tfd : uint32;
|
||||||
|
sec_count : uint32;
|
||||||
|
prdt_count : uint32;
|
||||||
|
b8 : puint16;
|
||||||
|
slot : uint32;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: Sending write DMA command');
|
||||||
|
|
||||||
|
reset_port(device^.port);
|
||||||
|
start_port(device^.port);
|
||||||
|
|
||||||
|
//prdt count is 22 bits
|
||||||
|
prdt_count := (count div 4194304) + 1;
|
||||||
|
|
||||||
|
if prdt_count > 32 then begin
|
||||||
|
send_write_dma := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use command slot 0 for the IDENTIFY command.
|
||||||
|
slot := find_cmd_slot(device);
|
||||||
|
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
|
||||||
|
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
|
||||||
|
cmd_header^.wrt := 1;
|
||||||
|
cmd_header^.prdtl := prdt_count;
|
||||||
|
cmd_header^.clear_busy := 1;
|
||||||
|
|
||||||
|
// Setup the command table (using slot 0)
|
||||||
|
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
|
||||||
|
|
||||||
|
for i:=0 to prdt_count - 1 do begin
|
||||||
|
cmd_table^.prdt[i].dba := vtop(uint32(buffer) + (i * 4194304));
|
||||||
|
|
||||||
|
if i = prdt_count - 1 then begin
|
||||||
|
cmd_table^.prdt[i].dbc := count - (i * 4194304) - 1; // 512 bytes (0-based count)
|
||||||
|
end else begin
|
||||||
|
cmd_table^.prdt[i].dbc := 4194304 - 1; // 512 bytes (0-based count)
|
||||||
|
end;
|
||||||
|
|
||||||
|
cmd_table^.prdt[i].int := 1; // Interrupt on completion
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Construct the Command FIS in the command table's CFIS area
|
||||||
|
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
|
||||||
|
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||||
|
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||||
|
fis^.c := $1;
|
||||||
|
fis^.command := ATA_CMD_WRITE_DMA_EXT;
|
||||||
|
fis^.device := $40; // LBA mode 48?
|
||||||
|
|
||||||
|
fis^.lba0 := lba and $FF;
|
||||||
|
fis^.lba1 := (
|
||||||
|
lba shr 8) and $FF;
|
||||||
|
fis^.lba2 := (
|
||||||
|
lba shr 16) and $FF;
|
||||||
|
fis^.lba3 := (
|
||||||
|
lba shr 24) and $FF;
|
||||||
|
fis^.lba4 := (
|
||||||
|
lba shr 32) and $FF;
|
||||||
|
|
||||||
|
fis^.countl := count and $FF;
|
||||||
|
fis^.counth := (
|
||||||
|
count shr 8) and $FF;
|
||||||
|
|
||||||
|
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||||
|
while (device^.port^.tfd and $88) <> 0 do begin
|
||||||
|
// console.writestring('AHCI: tfd: ');
|
||||||
|
// console.writehexln(device^.port^.tfd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||||
|
cmd := device^.port^.cmd_issue;
|
||||||
|
cmd := cmd or (1 shl slot);
|
||||||
|
device^.port^.cmd_issue := cmd;
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Sent write DMA command');
|
||||||
|
|
||||||
|
// Wait for command completion with a timeout.
|
||||||
|
timeout := 0;
|
||||||
|
repeat
|
||||||
|
cmd := device^.port^.cmd_issue; // Command Issue register
|
||||||
|
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
|
||||||
|
timeout := timeout + 10;
|
||||||
|
if timeout > 100000 then begin
|
||||||
|
console.writestringln('AHCI: Write DMA command timeout');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
// check for bit 30 in the tfd register
|
||||||
|
if (tfd and $40000000) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: error');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Command complete');
|
||||||
|
|
||||||
|
// Check for an error flag in the command register (bit 1)
|
||||||
|
if (cmd and (1 shl slot)) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: Error sending write DMA command');
|
||||||
|
|
||||||
|
// Check the error register for more information
|
||||||
|
console.writestring('AHCI: Error register: ');
|
||||||
|
console.writehexln(device^.port^.sata_error);
|
||||||
|
end;
|
||||||
|
|
||||||
|
send_write_dma := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//read atapi
|
||||||
|
function read_atapi(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
var
|
||||||
|
fis : PHBA_FIS_REG_H2D;
|
||||||
|
cmd_header : PHBA_CMD_HEADER;
|
||||||
|
cmd_table : PHBA_CMD_TABLE;
|
||||||
|
cmd : uint32;
|
||||||
|
i, timeout : uint32;
|
||||||
|
tfd : uint32;
|
||||||
|
sec_count : uint32;
|
||||||
|
prdt_count : uint32;
|
||||||
|
b8 : puint16;
|
||||||
|
slot : uint32;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: Sending read ATAPI command');
|
||||||
|
|
||||||
|
reset_port(device^.port);
|
||||||
|
start_port(device^.port);
|
||||||
|
|
||||||
|
//prdt count is 22 bits
|
||||||
|
prdt_count := (count div 4194304) + 1;
|
||||||
|
|
||||||
|
if prdt_count > 32 then begin
|
||||||
|
read_atapi := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use command slot 0 for the IDENTIFY command.
|
||||||
|
slot := find_cmd_slot(device);
|
||||||
|
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
|
||||||
|
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
|
||||||
|
cmd_header^.wrt := 0;
|
||||||
|
cmd_header^.prdtl := 1;
|
||||||
|
cmd_header^.atapi := 1;
|
||||||
|
|
||||||
|
// Setup the command table (using slot 0)
|
||||||
|
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
|
||||||
|
|
||||||
|
cmd_table^.prdt[0].dba := vtop(uint32(buffer));
|
||||||
|
cmd_table^.prdt[0].dbc := 512 - 1; // 512 bytes (0-based count
|
||||||
|
cmd_table^.prdt[0].int := 1; // Interrupt on completion
|
||||||
|
|
||||||
|
// Construct the Command FIS in the command table's CFIS area
|
||||||
|
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
|
||||||
|
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||||
|
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||||
|
fis^.c := $1;
|
||||||
|
fis^.command := ATA_CMD_PACKET;
|
||||||
|
fis^.device := $A0; // LBA mode 48?
|
||||||
|
|
||||||
|
fis^.featurel := fis^.featurel or 1; //setting both of these might not work on real hardware
|
||||||
|
fis^.featurel := fis^.featurel or (1 shl 2);
|
||||||
|
|
||||||
|
cmd_table^.acmd[0] := $A8; //ATAPI command
|
||||||
|
cmd_table^.acmd[1] := $0; //ATAPI command
|
||||||
|
|
||||||
|
cmd_table^.acmd[2] := uInt8((lba shr 24) and $FF);
|
||||||
|
cmd_table^.acmd[3] := uInt8((lba shr 16) and $FF);
|
||||||
|
cmd_table^.acmd[4] := uInt8((lba shr 8) and $FF);
|
||||||
|
cmd_table^.acmd[5] := uInt8(lba and $FF);
|
||||||
|
|
||||||
|
cmd_table^.acmd[9] := uInt8((1) and $FF);
|
||||||
|
|
||||||
|
|
||||||
|
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||||
|
while (device^.port^.tfd and $88) <> 0 do begin
|
||||||
|
// console.writestring('AHCI: tfd: ');
|
||||||
|
// console.writehexln(device^.port^.tfd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||||
|
cmd := device^.port^.cmd_issue;
|
||||||
|
cmd := cmd or (1 shl slot);
|
||||||
|
device^.port^.cmd_issue := cmd;
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Sent read ATAPI command');
|
||||||
|
|
||||||
|
// Wait for command completion with a timeout.
|
||||||
|
timeout := 0;
|
||||||
|
repeat
|
||||||
|
cmd := device^.port^.cmd_issue; // Command Issue register
|
||||||
|
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
|
||||||
|
timeout := timeout + 10;
|
||||||
|
if timeout > 100000 then begin
|
||||||
|
console.writestringln('AHCI: Read ATAPI command timeout');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
// check for bit 30 in the tfd register
|
||||||
|
if (tfd and $40000000) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: error');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Command complete');
|
||||||
|
|
||||||
|
// Check for an error flag in the command register (bit 1)
|
||||||
|
if (cmd and (1 shl slot)) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: Error sending read ATAPI command');
|
||||||
|
|
||||||
|
// Check the error register for more information
|
||||||
|
console.writestring('AHCI: Error register: ');
|
||||||
|
console.writehexln(device^.port^.sata_error);
|
||||||
|
end;
|
||||||
|
|
||||||
|
read_atapi := true;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -269,7 +269,7 @@ type
|
|||||||
pci_device : PPCI_Device;
|
pci_device : PPCI_Device;
|
||||||
mio: PHBA_Memory;
|
mio: PHBA_Memory;
|
||||||
ata_info : TIdentResponse;
|
ata_info : TIdentResponse;
|
||||||
devices : PDList;
|
devices : array[0..31] of TAHCI_Device;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
PAHCI_Controller = ^TAHCI_Controller;
|
PAHCI_Controller = ^TAHCI_Controller;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user