OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 2:13 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: AHCI Hardware error[Solved]
PostPosted: Tue Jul 31, 2018 3:08 pm 
Offline
Member
Member

Joined: Sat Sep 24, 2016 12:06 am
Posts: 90
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


Last edited by MrLolthe1st on Mon Aug 06, 2018 11:47 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: AHCI Hardware error
PostPosted: Tue Jul 31, 2018 7:43 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
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


Top
 Profile  
 
 Post subject: Re: AHCI Hardware error
PostPosted: Wed Aug 01, 2018 3:57 am 
Offline
Member
Member

Joined: Sat Sep 24, 2016 12:06 am
Posts: 90
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


Top
 Profile  
 
 Post subject: Re: AHCI Hardware error
PostPosted: Wed Aug 01, 2018 1:07 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
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


Top
 Profile  
 
 Post subject: Re: AHCI Hardware error
PostPosted: Wed Aug 01, 2018 3:32 pm 
Offline
Member
Member

Joined: Sat Sep 24, 2016 12:06 am
Posts: 90
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


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: 8infy and 63 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group