397 lines
11 KiB
ObjectPascal
397 lines
11 KiB
ObjectPascal
{ ************************************************
|
|
* Asuro
|
|
* Unit: Drivers/storage/IDE
|
|
* Description: IDE ATA Driver
|
|
*
|
|
************************************************
|
|
* Author: Aaron Hance
|
|
* Contributors:
|
|
************************************************ }
|
|
unit IDE;
|
|
|
|
interface
|
|
|
|
uses
|
|
util,
|
|
drivertypes,
|
|
console,
|
|
terminal,
|
|
isr76,
|
|
drivermanagement,
|
|
vmemorymanager,
|
|
lmemorymanager,
|
|
storagemanagement;
|
|
|
|
type
|
|
TIdentResponse = array[0..255] of uint16;
|
|
|
|
|
|
TIDE_Channel_Registers = record
|
|
base : uint16;
|
|
ctrl : uint16;
|
|
bmide : uint16;
|
|
noInter : uint8
|
|
end;
|
|
|
|
TIDE_Device = record
|
|
exists : boolean;
|
|
isPrimary : boolean;
|
|
isMaster : boolean;
|
|
isATAPI : boolean;
|
|
info : TIdentResponse;
|
|
end;
|
|
|
|
|
|
const
|
|
ATA_SR_BUSY = $80; //BUSY
|
|
ATA_SR_DRDY = $40; //DRIVE READY
|
|
ATA_SR_DF = $20; //DRIVE WRITE FAULT
|
|
ATA_SR_DSC = $10; //DRIVE SEEK COMPLETE
|
|
ATA_SR_DRQ = $08; //DATA REQUEST READY
|
|
ATA_SR_CORR = $04; //CORRECTED DATA
|
|
ATA_SR_IDX = $02; //INLEX
|
|
ATA_SR_ERR = $01; //ERROR
|
|
|
|
ATA_ER_BBK = $80; //BAD SECTOR
|
|
ATA_ER_UNC = $40; //UNCORRECTABLE DATA
|
|
ATA_ER_MC = $20; //NO MEDIA
|
|
ATA_ER_IDNF = $10; //ID MARK NOT FOUND
|
|
ATA_ER_MCR = $08; //NO MEDIA
|
|
ATA_ER_ABRT = $04; //COMMAND ABORTED
|
|
ATA_ER_TK0NF = $02; //TRACK 0 NOT FOUND
|
|
ATA_ER_AMNF = $01; //NO ADDRESS MARK
|
|
|
|
ATA_CMD_READ_PIO = $20;
|
|
ATA_CMD_READ_PIO_EXT = $24;
|
|
ATA_CMD_READ_DMA = $C8;
|
|
ATA_CMD_READ_DMA_EXT = $25;
|
|
ATA_CMD_WRITE_PIO = $30;
|
|
ATA_CMD_WRITE_PIO_EXT = $34;
|
|
ATA_CMD_WRITE_DMA = $CA;
|
|
ATA_CMD_WRITE_DMA_EXT = $35;
|
|
ATA_CMD_CACHE_FLUSH = $E7;
|
|
ATA_CMD_CACHE_FLUSH_EXT = $EA;
|
|
ATA_CMD_PACKET = $A0;
|
|
ATA_CMD_IDENTIFY_PACKET = $A1;
|
|
ATA_CMD_IDENTIFY = $EC;
|
|
|
|
ATAPI_CMD_READ = $A8;
|
|
ATAPI_CMD_EJECT = $1B;
|
|
|
|
ATA_IDENT_DEVICETYPE = $0;
|
|
ATA_IDENT_CYLINDERS = $2;
|
|
ATA_IDENT_HEADS = $6;
|
|
ATA_IDENT_SECOTRS = $12;
|
|
ATA_IDENT_SERIAL = $20;
|
|
ATA_IDENT_MODEL = $54;
|
|
ATA_IDENT_CAPABILITIES = $98;
|
|
ATA_IDENT_FIELDVALID = $106;
|
|
ATA_IDENT_MAX_LBA = $120;
|
|
ATA_IDENT_COMMANDSETS = $164;
|
|
ATA_IDENT_MAX_LBA_EXT = $200;
|
|
|
|
ATA_REG_DATA = $00;
|
|
ATA_REG_ERROR = $01;
|
|
ATA_REG_FEATURES = $01;
|
|
ATA_REG_SECCOUNT0 = $02;
|
|
ATA_REG_LBA0 = $03;
|
|
ATA_REG_LBA1 = $04;
|
|
ATA_REG_LBA2 = $05;
|
|
ATA_REG_HDDEVSEL = $06;
|
|
ATA_REG_COMMAND = $07;
|
|
ATA_REG_STATUS = $07;
|
|
ATA_REG_SECCOUNT1 = $08;
|
|
ATA_REG_LBA3 = $09;
|
|
ATA_REG_LBA4 = $0A;
|
|
ATA_REG_LBA5 = $0B;
|
|
ATA_REG_CONTROL = $0C;
|
|
ATA_REG_ALTSTATUS = $0C;
|
|
ATA_REG_DEVADDRESS = $0D;
|
|
|
|
var
|
|
controller : PPCI_Device;
|
|
|
|
bar0 : uint32;
|
|
bar1 : uint32;
|
|
bar4 : uint32;
|
|
|
|
IDEDevices : array[0..3] of TIDE_Device;
|
|
|
|
buffer : Puint32;
|
|
|
|
procedure init();
|
|
function load(ptr : void) : boolean;
|
|
function identify_device(bus : uint8; drive : uint8) : TIdentResponse;
|
|
procedure readPIO28(drive : uint8; LBA : uint32; sectorCount : uint8; buffer : puint32);
|
|
procedure writePIO28(drive : uint8; LBA : uint32; sectorCount : uint8; buffer : Puint32);
|
|
//read/write must be capable of reading/writting any amknt of data upto disk size
|
|
|
|
implementation
|
|
|
|
procedure test_command(params : PParamList);
|
|
var
|
|
secotrs : uint32;
|
|
cpacityMB : uint32;
|
|
buffer : puint32;
|
|
i : uint8;
|
|
begin
|
|
secotrs := IDEDevices[0].info[60];
|
|
secotrs := secotrs or (IDEDevices[0].info[61] shl 16);
|
|
|
|
cpacityMB := (secotrs * 512) DIV 1000 DIV 1000;
|
|
|
|
console.writestring('HHD_Primary_MASTER -');
|
|
console.writestring(' Capacity: ');
|
|
console.writeint(cpacityMB);
|
|
console.writestringln('MB');
|
|
|
|
buffer := puint32(kalloc(1024));
|
|
//buffer^:= secotrs;
|
|
|
|
for i:=0 to 20 do begin
|
|
puint32(buffer + (i div 2))^:= $10010110;
|
|
end;
|
|
|
|
writePIO28(0, 2, 1, buffer);
|
|
//buffer^:= $FFFF;
|
|
for i:=0 to 20 do begin
|
|
puint32(buffer + (i div 2))^:= $FFFFFFFF;
|
|
end;
|
|
|
|
readPIO28(0, 2, 1, buffer);
|
|
|
|
for i:=0 to 20 do begin
|
|
if puint32(buffer + (i div 2))^ <> $10010110 then begin
|
|
console.writestringln('Tests failed!');
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// if uint32(buffer^) = secotrs then begin
|
|
console.writestringln('Tests successful!');
|
|
// end
|
|
// else begin
|
|
// console.writestringln('Tests failed!');
|
|
// console.writehexln($01101001);
|
|
// console.writehexln(uint32(buffer^));
|
|
// end;
|
|
end;
|
|
|
|
procedure init();
|
|
var
|
|
devID : TDeviceIdentifier;
|
|
begin
|
|
console.writestringln('IDE ATA Driver: Init()');
|
|
devID.bus:= biPCI;
|
|
devID.id0:= idANY;
|
|
devID.id1:= $00000001;
|
|
devID.id2:= $00000001;
|
|
devID.id3:= idANY;
|
|
devID.id4:= idANY;
|
|
devID.ex:= nil;
|
|
drivermanagement.register_driver('IDE ATA Driver', @devID, @load);
|
|
terminal.registerCommand('IDE', @test_command, 'TEST IDE DRIVER');
|
|
buffer := Puint32(kalloc(1024*2));
|
|
end;
|
|
|
|
function load(ptr : void) : boolean;
|
|
var
|
|
storageDevice : TStorage_Device;
|
|
storageDevice1 : TStorage_Device;
|
|
begin
|
|
//controller := PPCI_Device(ptr);
|
|
|
|
|
|
//check if bus is floating and identify device
|
|
if inb($1F7) <> $FF then begin
|
|
outb($3F6, inb($3f6) or (1 shl 1)); // disable interrupts
|
|
IDEDevices[0].isMaster:= true;
|
|
IDEDevices[0].info := identify_device(0, $A0);
|
|
|
|
storageDevice.controller := ControllerIDE;
|
|
storageDevice.controllerId0:= 0;
|
|
storageDevice.maxSectorCount:= (IDEDevices[0].info[60] or (IDEDevices[0].info[61] shl 16) ); //LBA28 SATA
|
|
storageDevice.sectorSize:= 512;
|
|
if storageDevice.maxSectorCount <> 0 then begin
|
|
IDEDevices[0].exists:= true;
|
|
storagemanagement.register_device(@storageDevice);
|
|
end;
|
|
end;
|
|
|
|
if inb($1F7) <> $FF then begin
|
|
IDEDevices[1].isMaster:= false;
|
|
IDEDevices[1].info := identify_device(0, $B0);
|
|
|
|
storageDevice1.controller := ControllerIDE;
|
|
storageDevice1.controllerId0:= 0;
|
|
storageDevice1.maxSectorCount:= (IDEDevices[1].info[60] or (IDEDevices[1].info[61] shl 16) ); //LBA28 SATA
|
|
storageDevice1.sectorSize:= 512;
|
|
if storageDevice1.maxSectorCount <> 0 then begin
|
|
IDEDevices[1].exists:= true;
|
|
storagemanagement.register_device(@storageDevice1);
|
|
end;
|
|
end
|
|
|
|
end;
|
|
|
|
function identify_device(bus : uint8; drive : uint8) : TIdentResponse;
|
|
var
|
|
i : uint8;
|
|
identResponse : TIdentResponse;
|
|
t : uint32 = 0;
|
|
begin
|
|
if bus = 0 then begin
|
|
outb($1F6, drive); //drive select
|
|
|
|
outw($1F2, 0); //clear sector count and lba
|
|
outw($1F3, 0);
|
|
outw($1F4, 0);
|
|
outw($1F5, 0);
|
|
|
|
outw($1F7, ATA_CMD_IDENTIFY); //send identify command
|
|
console.writeint(1);
|
|
|
|
while true do begin
|
|
if (inw($1f7) and (1 shl 7)) = 0 then break; //Wait until drive not busy
|
|
end;
|
|
|
|
while true do begin
|
|
if (inw($1f7) and (1 shl 3)) <> 0 then break;
|
|
if (inw($1F7) and 1) <> 0 then exit; //drive error
|
|
if t > 100000 then exit; //todo return false
|
|
t +=1;
|
|
end;
|
|
|
|
for i:=0 to 254 do begin
|
|
identResponse[i] := inw($1F0); //read all bits
|
|
end;
|
|
|
|
identify_device:= identResponse;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
procedure writePIO28(drive : uint8; LBA : uint32; sectorCount : uint8; buffer : Puint32);
|
|
var
|
|
i : uint8;
|
|
ii : uint8;
|
|
iii : uint32;
|
|
begin
|
|
if IDEDevices[drive].isMaster then begin
|
|
outb($1F7, $E0 or ((LBA shr 24) and $0F)); //LBA command primary master
|
|
end
|
|
else begin
|
|
outb($1F7, $F0 or ((LBA shr 24) and $0F)); //LBA command primary slave
|
|
end;
|
|
|
|
outb($1F2, sectorCount);
|
|
outb($1F3, LBA);
|
|
outb($1F4, LBA shr 8);
|
|
outb($1F5, LBA shr 16);
|
|
outb($1F7, $30); //write command
|
|
|
|
for i:=0 to sectorCount do begin
|
|
|
|
//poll status
|
|
while true do if (inw($1f7) and (1 shl 7)) = 0 then break; //Wait until drive not busy
|
|
|
|
while true do begin
|
|
if (inw($1f7) and (1 shl 3)) <> 0 then break;
|
|
if (inw($1F7) and 1) <> 0 then begin
|
|
console.writestringln('write error');
|
|
exit;
|
|
end; //drive error
|
|
end;
|
|
|
|
for ii:=0 to 127 do begin //read data
|
|
outw($1F0, Puint32(buffer + ((i * 512) + (ii * 16) DIV 32) )^);
|
|
while true do if (inw($1f7) and (1 shl 7)) = 0 then break; //Wait until drive not busy
|
|
outb($1F7, $E7);
|
|
if ii <> 127 then begin
|
|
outw($1F0, Puint32(buffer + ((i * 512) + (ii * 16) DIV 32) )^ shr 16);
|
|
while true do if (inw($1f7) and (1 shl 7)) = 0 then break; //Wait until drive not busy
|
|
outb($1F7, $E7);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure readPIO28(drive : uint8; LBA : uint32; sectorCount : uint8; buffer : puint32);
|
|
var
|
|
i : uint8;
|
|
ii : uint8;
|
|
iii : uint32;
|
|
begin
|
|
if IDEDevices[drive].isMaster then begin
|
|
outb($1F7, $E0 or ((LBA shr 24) and $0F)); //read command primary master
|
|
end
|
|
else begin
|
|
outb($1F7, $F0 or ((LBA shr 24) and $0F)); //read command primary slave
|
|
end;
|
|
|
|
outb($1F2, sectorCount);
|
|
outb($1F3, LBA);
|
|
outb($1F4, LBA shr 8);
|
|
outb($1F5, LBA shr 16);
|
|
outb($1F7, $20); //read command
|
|
|
|
for i:=0 to sectorCount do begin
|
|
|
|
//poll status
|
|
while true do if (inw($1f7) and (1 shl 7)) = 0 then break; //Wait until drive not busy
|
|
|
|
while true do begin
|
|
if (inw($1f7) and (1 shl 3)) <> 0 then break;
|
|
if (inw($1F7) and 1) <> 0 then begin
|
|
console.writestringln('IDE read ERROR');
|
|
exit;
|
|
end; //drive error
|
|
end;
|
|
|
|
for ii:=0 to 127 do begin //read data
|
|
Puint32(buffer + ((i * 512) + (ii * 16) DIV 32))^ := uint32(inw($1F0)); //wrong
|
|
for iii:=0 to 1000 do if(ii = iii) then begin end;
|
|
if ii <> 127 then begin
|
|
Puint32(buffer + ((i * 512) + (ii * 16) DIV 32))^ := ((uint32(inw($1F0)) shl 16) or Puint32(buffer + ((i * 512) + (ii * 16) DIV 32))^); //wrong
|
|
for iii:=0 to 1000 do if(ii = iii) then begin end
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure readPIOPI(drive : uint8; LBA : uint32; buffer : Puint32);
|
|
var
|
|
i : uint16;
|
|
begin
|
|
if IDEDevices[drive].isMaster then begin
|
|
outb($1F7, $E0 or ((LBA shr 24) and $0F)); // command primary master
|
|
end
|
|
else begin
|
|
outb($1F7, $F0 or ((LBA shr 24) and $0F)); // command primary slave
|
|
end;
|
|
|
|
outb($1F2, 1);
|
|
outb($1F3, LBA);
|
|
outb($1F4, LBA shr 8);
|
|
outb($1F5, LBA shr 16);
|
|
outb($1F7, ATAPI_CMD_READ); //read command
|
|
|
|
//poll status
|
|
while true do if (inw($1f7) and (1 shl 7)) = 0 then break; //Wait until drive not busy
|
|
|
|
while true do begin
|
|
if (inw($1f7) and (1 shl 3)) <> 0 then break;
|
|
if (inw($1F7) and 1) <> 0 then begin
|
|
console.writestringln('IDE read ERROR');
|
|
exit;
|
|
end; //drive error
|
|
end;
|
|
|
|
// for i:=0 to 1023 do begin
|
|
// Puint32(buffer + (i * 1))^ := inw($1F0);
|
|
// end;
|
|
|
|
end;
|
|
|
|
end. |