Problems with SATA
Posted: Wed Nov 17, 2021 10:18 pm
So, in short, I'm having a lot of problems with SATA. I've read over the spec, and the samples in the wiki, and I'm not positive what I'm missing. Sadly, this caused me to shelf my OS project for over a year - it's not fun beating your head against a wall.
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:
The full source for my AHCI work is here: https://github.com/jwhitehorn/xv64/blob ... nel/ahci.c
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:
I appreciate any/all help you can provide, as I'd like to get this project moving again.
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;
}