What I'm seeing is this:
I can probe for AHCI devices, and identify them by their signature. I can even identify the SATA controller. I intiallize it by attempting to rebase it, which appears successful. However, when I attempt to read from it, that's when things go sideway. This is also the part where I'm certain I'm missing something.
Here is a sample of the boot log when my OS is starting:
Code: Select all
probing PCI...
PCI: 0:0.0: 8086:1237: class: 6.0 (Bridge device) irq: 0
PCI: 0:1.0: 8086:7000: class: 6.1 (Bridge device) irq: 0
PCI: 0:1.1: 8086:7010: class: 1.1 (Storage controller) irq: 0
PCI: 0:1.3: 8086:7113: class: 6.80 (Bridge device) irq: 9
PCI: 0:2.0: 1234:1111: class: 3.0 (Display controller) irq: 0
PCI: 0:3.0: 8086:2922: class: 1.6 (Storage controller) irq: 11 bar5: febf1000
Intel ICH9 controller found (bus=0, slot=3, func=0, abar=0xfebf1000)
HBA in legacy mode
SATA device detected:
port[1].sig = ffffffff
ipm=0, spd=0, det=3
rebasing port...DONE
here A
lower ptr=0000000000400000
upper ptr=0000000000000000
A.1
ptr: 0000000000400000
lock '(null)':
ffffffff80106f87 ffffffff80108858 ffffffff8010869e ffffffff80100da7 ffffffff80100775 ffffffff8010057f ffffffff8010a44e ffffffff8010a502 ffffffff8010a838 ffffffff8010abd5
PANIC on cpu 0
acquire
STACK:
[0] ffffffff801016eb
[1] ffffffff80106f47
[2] ffffffff80108ae5
[3] ffffffff8010886a
[4] ffffffff8010869e
[5] ffffffff80100da7
[6] ffffffff80100775
[7] ffffffff8010057f
[8] ffffffff8010a44e
[9] ffffffff8010a502
HLT
But, the bits for reading from the device are not checked in (because they're all hacked up and failing). The logic looks like this:
Code: Select all
void ahci_sata_init(HBA_PORT *port, int num){
if(ahci_rebase_port(port,num) > 0) {
//TODO: rest of init
uint16 buf[16];
int success = ahci_sata_read(port, 0, 0, 1, &buf[0]);
if(success == 1){
cprintf("SUCCESS READING SATA!\n");
}else{
cprintf("BOO!!!!!!\n");
}
}
}
int ahci_sata_read(HBA_PORT *port, uint32 startl, uint32 starth, uint32 count, uint16 *buf) {
port->is = (uint32) -1; // Clear pending interrupt bits
int spin = 0; // Spin lock timeout counter
int slot = ahci_find_cmdslot(port);
if (slot == -1)
return 0;
cprintf("here A\n");
cprintf("lower ptr=%p\n", port->clb);
cprintf("upper ptr=%p\n", port->clbu);
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER*) (
((uint64)port->clbu << 32) + port->clb
);
cmdheader += slot;
cprintf("A.1\n");
cprintf("ptr: %p\n", cmdheader);
cmdheader->cfl = sizeof(FIS_REG_H2D)/sizeof(uint32); // Command FIS size
cprintf("A.2\n");
cmdheader->w = 0; // Read from device
cprintf("A.3\n");
cmdheader->prdtl = (uint16)((count-1)>>4) + 1; // PRDT entries count
cprintf("here B\n");
HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL*)((uint64)cmdheader->ctba);
memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) +
(cmdheader->prdtl-1)*sizeof(HBA_PRDT_ENTRY));
cprintf("here C\n");
int i = 0;
// 8K bytes (16 sectors) per PRDT
for (i=0; i<cmdheader->prdtl-1; i++){
cmdtbl->prdt_entry[i].dba = (uint32) *buf;
cmdtbl->prdt_entry[i].dbc = 8*1024-1; // 8K bytes (this value should always be set to 1 less than the actual value)
cmdtbl->prdt_entry[i].i = 1;
buf += 4*1024; // 4K words
count -= 16; // 16 sectors
}
cprintf("here D\n");
// Last entry
cmdtbl->prdt_entry[i].dba = (uint32) *buf;
cmdtbl->prdt_entry[i].dbc = (count<<9)-1; // 512 bytes per sector
cmdtbl->prdt_entry[i].i = 1;
cprintf("here E\n");
// Setup command
FIS_REG_H2D *cmdfis = (FIS_REG_H2D*)(&cmdtbl->cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1; // Command
cmdfis->command = ATA_CMD_READ_DMA_EX;
cmdfis->lba0 = (uint8)startl;
cmdfis->lba1 = (uint8)(startl>>8);
cmdfis->lba2 = (uint8)(startl>>16);
cmdfis->device = 1<<6; // LBA mode
cmdfis->lba3 = (uint8)(startl>>24);
cmdfis->lba4 = (uint8)starth;
cmdfis->lba5 = (uint8)(starth>>8);
cmdfis->countl = count & 0xFF;
cmdfis->counth = (count >> 8) & 0xFF;
cprintf("here F\n");
// The below loop waits until the port is no longer busy before issuing a new command
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
spin++;
}
if (spin == 1000000) {
cprintf("Port is hung\n");
return 0;
}
cprintf("here G\n");
port->ci = 1<<slot; // Issue command
// Wait for completion
while (1){
// In some longer duration reads, it may be helpful to spin on the DPS bit
// in the PxIS port field as well (1 << 5)
if ((port->ci & (1<<slot)) == 0)
break;
if (port->is & HBA_PxIS_TFES){ // Task file error
cprintf("Read disk error\n");
return 0;
}
}
cprintf("here H\n");
// Check again
if (port->is & HBA_PxIS_TFES){
cprintf("Read disk error\n");
return 0;
}
cprintf("here I\n");
return 1;
}