I continue having problems with the AHCI controller: the Identify Device command (0xEC in ATA Command Set) doesn't work in VirtualBox. I know that there are one device in the port 0 (I've configured it in VirtualBox and I have read it from the PI register in HBA MEM), but when I issue the command which has the Identify Device command, the HBA enables the bit ERR(bit 0) in the TFD register in the port 0.
The code which issue the Identify command is the following:
Code: Select all
s32 AHCI_IdentifyDev(u8 p, u8* mem){
if(p > 31) return 0x01;
u32 pi = AHCI_MMIO_READ(_hba_mem->pi);
if(!(pi & (1 << p))) return 0x02;
if(mem == NULL) return 0x03;
if(((u32)mem) & 1) return 0x04; // !Alineamiento PAR
HBA_Port* port = &(_hba_mem->ports[p]);
u32 ssts = AHCI_MMIO_READ(port->ssts);
if(SSTS_DET(ssts) == 0x00) return 0x05;
if(SSTS_IPM(ssts) == 0x00) return 0x06;
AHCI_StopCMD(p);
u8 cmd_slot = AHCI_PORT_FindFreeCmdSlot(p);
if(cmd_slot > 31) return 0x07;
HBA_CmdHeader* hdr = (HBA_CmdHeader*) AHCI_MMIO_READ(port->clb);
hdr += cmd_slot;
hdr->cfl = 5;
if(port->cmd & CMD_ATAPI) hdr->a = 1;
else hdr->a = 0;
hdr->prdtl = 0x01;
HBA_CmdTable* table = (HBA_CmdTable*) hdr->ctba;
memset(table, 0x00, sizeof (HBA_CmdTable) + (hdr->prdtl) * sizeof(HBACMD_PRDT));
table->prdt[0].dba = (u32)mem;
table->prdt[0].dbau = 0x00;
table->prdt[0].dbc = 512;
table->prdt[0].i = 1;
FIS_RegH2D* reg = (FIS_RegH2D*)table->cfis;
reg->type = FIS_REGISTER_H2D;
reg->c = 1;
if(port->cmd & CMD_ATAPI) reg->cmd = 0xA1;
else reg->cmd = 0xEC;
AHCI_PORT_Wait4Free(p);
u32 sact = AHCI_MMIO_READ(port->sact);
sact |= (1 << cmd_slot);
AHCI_MMIO_WRITE(sact, port->sact);
u32 ci = AHCI_MMIO_READ(port->ci);
ci |= (1 << cmd_slot);
AHCI_MMIO_WRITE(ci, port->ci);
AHCI_StartCMD(p);
u32 is, err;
while(1){
ci = AHCI_MMIO_READ(port->ci);
sact = AHCI_MMIO_READ(port->sact);
if(!((ci | sact) & (1 << cmd_slot))) break;
is = AHCI_MMIO_READ(port->is);
if(is & IS_TFES) return 0x08;
err = AHCI_MMIO_READ(port->tfd);
if(err & TFD_STS_ERR) return 0x09;
}
is = AHCI_MMIO_READ(port->is);
if(is & IS_TFES) return 0x08;
return 0x00;
}