Code: Select all
dev->port->is = dev->port->is;
// we don't need to protect the device with semaphores, because only this thread
// accesses its port.
// first find a free command slot; we may wait for some time if the drive is
// particularly busy.
uint32_t slot = 0;
while (dev->port->ci & (1 << slot))
{
slot = (slot + 1) % 32;
__sync_synchronize();
};
// fill in the appropriate structure.
// do not zero it; it was already zeroed before and only this thread updates the
// structures so we know that any unused fields are already zero.
cmdhead[slot].cfl = sizeof(FIS_REG_H2D)/4;
cmdhead[slot].w = 0;
cmdhead[slot].prdtl = 1;
__sync_synchronize();
AHCICommandTable *cmdtbl = (AHCICommandTable*) ((char*)dmaGetPtr(&dev->dmabuf) + 1024+256+8*1024+256*slot);
cmdtbl->prdt_entry[0].dba = dmaGetPhys(&dev->iobuf) + 4096*slot;
cmdtbl->prdt_entry[0].dbc = 512*cmd->count;
cmdtbl->prdt_entry[0].i = 0;
FIS_REG_H2D *cmdfis = (FIS_REG_H2D*)(&cmdtbl->cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1;
if (cmd->type == SD_CMD_READ)
{
cmdfis->command = ATA_CMD_READ_DMA_EXT;
}
else
{
cmdfis->command = ATA_CMD_WRITE_DMA_EXT;
};
cmdfis->lba0 = (uint8_t)cmd->index;
cmdfis->lba1 = (uint8_t)(cmd->index>>8);
cmdfis->lba2 = (uint8_t)(cmd->index>>16);
cmdfis->device = 1<<6; // LBA mode
cmdfis->lba3 = (uint8_t)(cmd->index>>24);
cmdfis->lba4 = (uint8_t)(cmd->index>>32);
cmdfis->lba5 = (uint8_t)(cmd->index>>40);
cmdfis->countl = (uint8_t)(cmd->count);
cmdfis->counth = (uint8_t)(cmd->count>>8);
char *hwbuf = (char*) dmaGetPtr(&dev->iobuf) + (4096*slot);
if (cmd->type == SD_CMD_WRITE)
{
memcpy(hwbuf, cmd->block, 512*cmd->count);
};
// wait for the port to stop being busy
int busy = (1 << 7) | (1 << 3);
while (dev->port->tfd & busy) __sync_synchronize();
__sync_synchronize();
if (dev->port->tfd & (1 << 0))
{
panic("AHCI transfer error!");
};
dev->port->ci = (1 << slot);
__sync_synchronize();
while (dev->port->ci & (1 << slot))
{
if (dev->port->is & (1 << 27))
{
panic("AHCI error!");
};
__sync_synchronize();
};
__sync_synchronize();
if (cmd->type == SD_CMD_READ)
{
memcpy(cmd->block, hwbuf, 512*cmd->count);
};