OSDev.org https://forum.osdev.org/ |
|
AHCI Hardware error[Solved] https://forum.osdev.org/viewtopic.php?f=1&t=33095 |
Page 1 of 1 |
Author: | MrLolthe1st [ Tue Jul 31, 2018 3:08 pm ] |
Post subject: | AHCI Hardware error[Solved] |
Hi! Today i'm wrote my own AHCI driver, but on real hardware after command issue i'm get 0x4000000 to "interrupt status" register, on QEMU, VBox everything is ok. What it may be? With best regards, Aleksandr |
Author: | BenLunt [ Tue Jul 31, 2018 7:43 pm ] |
Post subject: | Re: AHCI Hardware error |
MrLolthe1st wrote: Hi! Today i'm wrote my own AHCI driver, but on real hardware after command issue i'm get 0x4000000 to "interrupt status" register, on QEMU, VBox everything is ok. What it may be? With best regards, Aleksandr This is why I asked in the EHCI thread if your machine was little-endian or big-endian. If your machine is big-endian and you are reading that dword, bit 30 is set which would be the same as if it was bit 1 in little-endian format (so-to-speak[1]). Bit 1 is port 1, the port your drive most likely is on. I think you might have a big-endian, little-endian issue. Just a thought, Ben [1]Technically, it would be 0x02000000, but 0x40000000 is the second bit from the left while 0x00000002 is the second bit from the right. Is this coincidence or are you getting your bit positions mixed up? On a little-endian machine (Intel, AMD, etc), bit 0 is the far right bit while bit 31 is the far left bit. Code: Bit 31 30 29 28 27 ... 5 4 3 2 1 0
0x40000000 ; <- bit 30 0x00000002 ; <- bit 1 |
Author: | MrLolthe1st [ Wed Aug 01, 2018 3:57 am ] |
Post subject: | Re: AHCI Hardware error |
I'm know about big-endian and little-endian. All my PCs and virtual machines are little-endian, there are not any troubles with bit order. There are some troubles with my realisation, may by. May be i'm need to align address to 4096 bytes when port rebase, my malloc returns me not-aligned address of memory, in EHCI i'm allocate to queue pool, td pool, framelist and say to malloc to allocate more then need by 8192 bytes and i'm do that: qhPool = ((uint)qhPool)/4096)*4096 + 4096; for td pool, qh pool, and framelist There is my code of read and other: Code: void port_rebase(HBA_PORT *port, int portno) { stop_cmd(port); // Stop command engine // Command list offset: 1K*portno // Command list entry size = 32 // Command list entry maxim count = 32 // Command list maxim size = 32*32 = 1K per port port->clb = malloc(1024); port->clbu = 0; memset((void*)(port->clb), 0, 1024); // FIS offset: 32K+256*portno // FIS entry size = 256 unsigned chars per port port->fb = malloc(256); port->fbu = 0; memset((void*)(port->fb), 0, 256); // Command table offset: 40K + 8K*portno // Command table size = 256*32 = 8K per port HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER*)(port->clb); for (int i = 0; i<32; i++) { cmdheader[i].prdtl = 8; // 8 prdt entries per command table // 256 unsigned chars per command table, 64+16+48+16*8 // Command table offset: 40K + 8K*portno + cmdheader_index*256 cmdheader[i].ctba = malloc(256); cmdheader[i].ctbau = 0; memset((void*)cmdheader[i].ctba, 0, 256); } start_cmd(port); // Start command engine } // Start command engine void start_cmd(HBA_PORT *port) { // Wait until CR (bit15) is cleared while (port->cmd & HBA_PxCMD_CR) //kprintf("cmd: %d %d\n", port->cmd, port->cmd & HBA_PxCMD_CR); ; port->cmd |= HBA_PxCMD_FRE; port->cmd |= HBA_PxCMD_ST; } // Stop command engine void stop_cmd(HBA_PORT *port) { // kprintf("%x\n", port->cmd); // Clear ST (bit0) port->cmd &= ~HBA_PxCMD_ST; port->cmd &= ~HBA_PxCMD_FRE; //port->cmd &= ~HBA_PxCMD_FRE; // Wait until FR (bit14), CR (bit15) are cleared while (1) { if (port->cmd & HBA_PxCMD_FR) continue; if (port->cmd & HBA_PxCMD_CR) continue; break; } // Clear FRE (bit4) } #define HBA_PxIS_TFES (1 << 30) bool read(HBA_PORT *port, unsigned long long starth, uint32_t count, uint16_t *buf) { port->is = 0xffff; // Clear pending interrupt bits int slot = find_cmdslot(port); if (slot == -1) return 0; uint64_t addr = 0; addr = (((addr | port->clbu) << 32) | port->clb); HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER*)(KERNBASE + addr); cmdheader += slot; cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(unsigned int); // Command FIS size cmdheader->w = 0; // Read from device cmdheader->c = 1; // Read from device cmdheader->p = 1; // Read from device cmdheader->prdtl = (unsigned short)((count - 1) >> 4) + 1; // PRDT entries count addr = 0; addr = (((addr | cmdheader->ctbau) << 32) | cmdheader->ctba); HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL*)(KERNBASE + addr); int i = 0; for (i = 0; i < cmdheader->prdtl - 1; i++) { cmdtbl->prdt_entry[i].dba = (unsigned int)(buf) & 0xFFFFFFFF; cmdtbl->prdt_entry[i].dbau = 0; cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K unsigned chars cmdtbl->prdt_entry[i].i = 0; buf += 4 * 1024; // 4K unsigned shorts count -= 16; // 16 sectors } cmdtbl->prdt_entry[i].dba = (unsigned int)(buf) & 0xFFFFFFFF; cmdtbl->prdt_entry[i].dbau = 0; cmdtbl->prdt_entry[i].dbc = count << 9; // 512 unsigned chars per sector cmdtbl->prdt_entry[i].i = 0; FIS_REG_H2D *cmdfis = (FIS_REG_H2D*)(&cmdtbl->cfis); cmdfis->fis_type = FIS_TYPE_REG_H2D; cmdfis->c = 1; // Command cmdfis->command = 0x25; cmdfis->lba0 = (unsigned char)starth; cmdfis->lba1 = (unsigned char)(starth >> 8); cmdfis->lba2 = (unsigned char)(starth >> 16); cmdfis->device = 1 << 6; // LBA mode cmdfis->lba3 = (unsigned char)(starth >> 24); cmdfis->lba4 = (unsigned char)(starth >> 32); cmdfis->lba5 = (unsigned char)(starth >> 40); cmdfis->countl = count & 0xff; cmdfis->counth = count >> 8; //kprintf("[slot]{%d}", slot); port->ci = 1 << slot; // Issue command port->is = ~0; // Issue command while (1) { kprintf("[%x,%x]", port->ci, port->is); if ((port->ci & (1 << slot)) == 0) break; if ((port->is & (1<<26)) != 0) { // Task file error kprintf("SATA Error\n"); return 0; } if (port->is & HBA_PxIS_TFES) { // Task file error kprintf("Read disk error\n"); return 0; } } if ((port->is & (1 << 26)) != 0) { // Task file error kprintf("SATA Error\n"); return 0; } if (port->is & HBA_PxIS_TFES) { kprintf("Read disk error\n"); return 0; } int k = 0; while (port->ci != 0) { k++; if (k > 10) return 0; PitWait(1000); kprintf("[%d]", port->ci); } return 1; } // Find a free command list slot int find_cmdslot(HBA_PORT *m_port) { // If not set in SACT and CI, the slot is free uint32_t slots = (m_port->sact | m_port->ci); uint qq = (abar->cap & 0x0f00) >> 8; for (int i = 0; i<qq; i++) { if ((slots & 1) == 0) return i; slots >>= 1; } kprintf("Cannot find free command list entry\n"); return -1; } void _probe_port(HBA_MEM *abar_temp) { // Search disk in impelemented ports uint pi = abar_temp->pi; int i = 0; while (i < 32) { if (pi & 1) { int dt = check_type((HBA_PORT *)&abar_temp->ports[i]); if (dt == AHCI_DEV_SATA) { kprintf("SATA drive found at port %d\n", i); abar = abar_temp; port_rebase(&abar_temp->ports[i], i); kprintf("DONE AHCI INITIALISATION"); unsigned short * buf = malloc(16 * 512); buf[0] = 1; kprintf("qqqss"); int res = 0; int jj = 0; while (res == 0) { res = read(&abar->ports[i], 16*jj, 1, buf); if (res != 0) for (int z = 0; z < 256; z++) { kprintf(" %x", buf[z]); } PitWait(10000); jj++; } } else if (dt == AHCI_DEV_SATAPI) { //kprintf("\nSATAPI drive found at port %d\n", i); } else if (dt == AHCI_DEV_SEMB) { //kprintf("\nSEMB drive found at port %d\n", i); } else if (dt == AHCI_DEV_PM) { //kprintf("\nPM drive found at port %d\n", i); } else { //kprintf("\nNo drive found at port %d\n", i); } } pi >>= 1; i++; } kprintf("probe_port complete\n"); } With best regards, Aleksandr |
Author: | BenLunt [ Wed Aug 01, 2018 1:07 pm ] |
Post subject: | Re: AHCI Hardware error |
If I remember correctly, the HBA also needs you to read and write full dwords. See the comments I made in the EHCI thread (URL noted earlier) about reading and writing to mem-mapped I/O space. Assuming 32-bit addresses, simple *external* functions such as: Code: bit32u mem_read_io_regs(const bit32u base, const bit32u offset) { return * ((volatile bit32u *) (base + offset)); } void mem_write_io_regs(const bit32u base, const bit32u offset, const bit32u val) { volatile bit32u *ptr = (volatile bit32u *) (base + offset); *ptr = val; } A 64-bit read or write is very similar. However, and this is a big however, you need to be aware that some hardware wants the low dword written first, while some hardware wants the high dword written first. For example, one of the Network Adapters that I am currently researching will execute the command when the low dword is written, not the high-dword. i.e.: It expects the high dword to have already been written when writing the low dword. Another example is a 64-bit high-speed timer. For example, if you read the low dword and then read the high dword, the high dword could have changed while reading the low dword and you now can be off by a 4Gig value. Change your code as suggested and see if this fixes it. Ben - http://www.fysnet.net/osdesign_book_series.htm |
Author: | MrLolthe1st [ Wed Aug 01, 2018 3:32 pm ] |
Post subject: | Re: AHCI Hardware error |
Hi, Ben. I'm changed compiler, do as you say and there aren't any effect Replied to EHCI topic too. Can you give to me your implementation of EHCI driver? I guess, that your driver works fine. With best regards, Aleksandr |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |