OSDev.org

The Place to Start for Operating System Developers
It is currently Sun Apr 28, 2024 10:47 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: AHCI controller reports success but reads no data
PostPosted: Mon Nov 13, 2023 4:54 pm 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
My AHCI driver works correctly in VirtualBox, I'm able to read and write sectors and perform a full installation of my OS. On my physical machine, I'm getting some strange behaviour. It successfully initializes the port, sends an IDENTIFY command, and receives the correct disk size and name, and PRDC is set to 0x200 after this operation - the correct size. Here is the code for ataInit(), where the IDENTIFY command is sent:

Code:
void ataInit(AHCIController *ctrl, int portno)
{
   ATADevice *dev = NEW(ATADevice);
   ctrl->ataDevices[ctrl->numAtaDevices++] = dev;
   mutexInit(&dev->lock);
   
   dev->ctrl = ctrl;
   dev->port = &ctrl->regs->ports[portno];
   dev->sd = NULL;
   
   // create the operations area
   if (dmaCreateBuffer(&dev->dmabuf, sizeof(AHCIOpArea), 0) != 0)
   {
      // it didn't work
      kprintf("sdahci: failed to allocate operations area\n");
      kfree(dev);
      ctrl->numAtaDevices--;
      return;
   };
   
   // set up the operations area
   AHCIOpArea *opArea = (AHCIOpArea*) dmaGetPtr(&dev->dmabuf);
   memset(opArea, 0, sizeof(AHCIOpArea));
   
   // set the command list and FIS area
   dev->port->clb = dmaGetPhys(&dev->dmabuf) + __builtin_offsetof(AHCIOpArea, cmdlist);
   dev->port->fb = dmaGetPhys(&dev->dmabuf) + __builtin_offsetof(AHCIOpArea, fisArea);
   
   // we only use the first command header, so initialize it to point to the table
   opArea->cmdlist[0].ctba = dmaGetPhys(&dev->dmabuf) + __builtin_offsetof(AHCIOpArea, cmdtab);
   
   // start the command engine
   ahciStartCmd(dev->port);
   dev->port->serr = dev->port->serr;
   dev->port->is = dev->port->is;
   
   // send the IDENTIFY command.
   opArea->cmdlist[0].cfl = sizeof(FIS_REG_H2D)/4;      // FIS length in dwords
   opArea->cmdlist[0].w = 0;            // read data
   opArea->cmdlist[0].prdtl = 1;            // only one PRDT entry
   opArea->cmdlist[0].p = 1;
   
   opArea->cmdtab.prdt[0].dba = dmaGetPhys(&dev->dmabuf) + __builtin_offsetof(AHCIOpArea, id);
   opArea->cmdtab.prdt[0].dbc = 511;         // length-1
   opArea->cmdtab.prdt[0].i = 0;            // do not interrupt
   
   // set up command FIS
   FIS_REG_H2D *cmdfis = (FIS_REG_H2D*) opArea->cmdtab.cfis;
   cmdfis->fis_type = FIS_TYPE_REG_H2D;
   cmdfis->c = 1;
   cmdfis->command = ATA_CMD_IDENTIFY;
   
   // issue the command and await completion
   __sync_synchronize();
   if (ahciIssueCmd(dev->port) != 0)
   {
      kprintf("sdahci: error during identification\n");
      return;
   };

   kprintf("IDENTIFY PRDC: 0x%08x\n", opArea->cmdlist[0].prdbc);
   sleep(8000);
   
   uint32_t *cmdsetptr = (uint32_t*) &opArea->id[ATA_IDENT_COMMANDSETS];
   
   uint32_t cmdset = *cmdsetptr;
   uint64_t size;
   if (cmdset & (1 << 26))
   {
      uint64_t *szptr = (uint64_t*) &opArea->id[ATA_IDENT_MAX_LBA_EXT];
      size = (*szptr) & 0xFFFFFFFFFFFF;
   }
   else
   {
      uint32_t *szptr = (uint32_t*) &opArea->id[ATA_IDENT_MAX_LBA];
      size = (uint64_t) (*szptr);
   };

   char model[41];
   int k;
   for (k=0; k<40; k+=2)
   {
      model[k] = opArea->id[ATA_IDENT_MODEL + k + 1];
      model[k+1] = opArea->id[ATA_IDENT_MODEL + k];
   };
   model[40] = 0;
   char *check = &model[39];
   while (*check == ' ')
   {
      if (check == model) break;
      *check-- = 0;
   };

   kprintf("sdahci: size in MB: %lu, model: %s\n", size / 1024 / 2, model);
   
   SDParams sdpars;
   sdpars.flags = 0;
   sdpars.blockSize = 512;
   sdpars.totalSize = size * 512;

   // do a cache flush
   opArea->cmdlist[0].w = 0;
   opArea->cmdlist[0].p = 0;
   opArea->cmdlist[0].c = 1;
   opArea->cmdlist[0].prdtl = 0;

   cmdfis->fis_type = FIS_TYPE_REG_H2D;
   cmdfis->c = 1;
   cmdfis->command = ATA_CMD_CACHE_FLUSH_EXT;
   
   cmdfis->lba0 = 0;
   cmdfis->lba1 = 0;
   cmdfis->lba2 = 0;
   cmdfis->device = 1<<6;   // LBA mode

   cmdfis->lba3 = 0;
   cmdfis->lba4 = 0;
   cmdfis->lba5 = 0;
   
   cmdfis->countl = 0;
   cmdfis->counth = 0;
   
   // issue the flush command
   int status = ahciIssueCmd(dev->port);
   kprintf("sdahci: cache flush status: %d\n", status);
   
   dev->sd = sdCreate(&sdpars, model, &ataOps, dev);
   if (dev->sd == NULL)
   {
      kprintf("sdahci: SD creation failed\n");
      // NOTE: do not free anything; this is done upon removing the driver
   };
};


It prints "IDENTIFY PRDC: 0x200" on real hardware. ahciIssueCmd() is defined as:

Code:
int ahciIssueCmd(volatile AHCIPort *port)
{
   uint64_t startTime = getNanotime();
   
   port->is = port->is;
   port->ci = 1;
   
   while (1)
   {
      if (getNanotime()-startTime > 8*NANO_PER_SEC)
      {
         // taking longer than 8 seconds
         kprintf("sdahci: timeout; aborting command. IS=0x%08X, SERR=0x%08X, TFD=0x%08X\n", port->is, port->serr, port->tfd);
         ahciStopCmd(port);
         ahciStartCmd(port);
         port->serr = port->serr;
         return EIO;
      };
      
      if (port->is & IS_ERR_FATAL)
      {
         // a fatal error occured
         kprintf("sdahci: fatal error. IS=0x%08X, SERR=0x%08X\n", port->is, port->serr);
         
         ahciStopCmd(port);
         ahciStartCmd(port);
         port->serr = port->serr;
         return EIO;
      };
      
      if ((port->ci & 1) == 0)
      {
         break;
      };
   };
   
   int busy = STS_BSY | STS_DRQ;
   while (port->tfd & busy)
   {
      if (getNanotime()-startTime > 8*NANO_PER_SEC)
      {
         kprintf("sdahci: timeout; aborting command. IS=0x%08X, SERR=0x%08X, TFD=0x%08X\n", port->is, port->serr, port->tfd);
         ahciStopCmd(port);
         ahciStartCmd(port);
         port->serr = port->serr;
         return EIO;
      };
   };
   
   if (port->tfd & STS_ERR)
   {
      return EIO;
   };
   
   return 0;
};


And here is how I implement reading, along with some deubgging:

Code:
int ataTransferBlocks(ATADevice *dev, size_t startBlock, size_t numBlocks, void *buffer, int dir)
{
   mutexLock(&dev->lock);
   
   AHCIOpArea *opArea = (AHCIOpArea*) dmaGetPtr(&dev->dmabuf);
   opArea->cmdlist[0].cfl = sizeof(FIS_REG_H2D) / 4;
   opArea->cmdlist[0].c = 1;            // clear BSY when done
   
   if (dir == ATA_READ)
   {
      opArea->cmdlist[0].w = 0;
      opArea->cmdlist[0].p = 1;
   }
   else
   {
      opArea->cmdlist[0].w = 1;
      opArea->cmdlist[0].p = 0;
   };

   uint16_t prdtl = 0;
   
   DMARegion reg;
   for (dmaFirstRegion(&reg, buffer, 512*numBlocks, 0); reg.physAddr!=0; dmaNextRegion(&reg))
   {
      if (prdtl == 9) panic("unexpected input");

      if (dir == ATA_READ && startBlock == 0)
      {
         kprintf("ATA_READ 0: Region: physAddr=0x%016lX, physSize=0x%04lX\n", reg.physAddr, reg.physSize);
      };
      
      opArea->cmdtab.prdt[prdtl].dba = reg.physAddr;
      opArea->cmdtab.prdt[prdtl].dbc = reg.physSize - 1;
      opArea->cmdtab.prdt[prdtl].i = 0;
      
      prdtl++;
   };
   
   opArea->cmdlist[0].prdtl = prdtl;

   FIS_REG_H2D *cmdfis = (FIS_REG_H2D*)(&opArea->cmdtab.cfis);
   cmdfis->fis_type = FIS_TYPE_REG_H2D;
   cmdfis->c = 1;
   if (dir == ATA_READ)
   {
      cmdfis->command = ATA_CMD_READ_DMA_EXT;
   }
   else
   {
      cmdfis->command = ATA_CMD_WRITE_DMA_EXT;
   };
   
   cmdfis->lba0 = (uint8_t)startBlock;
   cmdfis->lba1 = (uint8_t)(startBlock>>8);
   cmdfis->lba2 = (uint8_t)(startBlock>>16);
   cmdfis->lba3 = (uint8_t)(startBlock>>24);
   cmdfis->lba4 = (uint8_t)(startBlock>>32);
   cmdfis->lba5 = (uint8_t)(startBlock>>40);
   cmdfis->device = 1<<6;   // LBA mode
   
   cmdfis->countl = numBlocks & 0xFF;
   cmdfis->counth = (numBlocks >> 8) & 0xFF;
   
   // issue the command
   int status = ahciIssueCmd(dev->port);
   if (status != 0)
   {
      mutexUnlock(&dev->lock);
      return status;
   };

   kprintf("PRDC: 0x%08x, IS=0x%08x, SERR=0x%08x\n", opArea->cmdlist[0].prdbc, dev->port->is, dev->port->serr);
   
   // do a cache flush
   opArea->cmdlist[0].w = 0;
   opArea->cmdlist[0].p = 0;
   opArea->cmdlist[0].c = 1;
   opArea->cmdlist[0].prdtl = 0;

   cmdfis->fis_type = FIS_TYPE_REG_H2D;
   cmdfis->c = 1;
   cmdfis->command = ATA_CMD_CACHE_FLUSH_EXT;
   
   cmdfis->lba0 = 0;
   cmdfis->lba1 = 0;
   cmdfis->lba2 = 0;
   cmdfis->device = 1<<6;   // LBA mode

   cmdfis->lba3 = 0;
   cmdfis->lba4 = 0;
   cmdfis->lba5 = 0;
   
   cmdfis->countl = 0;
   cmdfis->counth = 0;
   
   // issue the flush command
   status = ahciIssueCmd(dev->port);
   mutexUnlock(&dev->lock);
   return status;
};

int ataReadBlocks(void *drvdata, size_t startBlock, size_t numBlocks, void *buffer)
{
   // DEBUG
   memset(buffer, 0, 512 * numBlocks);

   ATADevice *dev = (ATADevice*) drvdata;
   int result = ataTransferBlocks(dev, startBlock, numBlocks, buffer, ATA_READ);

   if (startBlock == 0)
   {
      kprintf("Dumping first sector of ATA drive:");

      uint8_t *buf = (uint8_t*) buffer;
      for (size_t i=0; i<512; i++)
      {
         if ((i % 32) == 0)
         {
            kprintf("\n");
         };

         kprintf("%02hhx ", buf[i]);
      };

      kprintf("\nEND OF DUMP\n");
   };

   return result;
};



In VirtualBox, the read operation works too. It reports no errors (PxSERR = 0), and PRDC=0x8000, the requested size. The debugging code prints the regions it iterates over when building the PRDT, there are a few regions all of which are page-aligned and page-sized (That is, each one is a single page). It prints the correct hex dump of the first sector, where I can clearly see the boot signature.

But on physical hardware, the IDENTIFY command succeeds as I mentioned, but something strange happens with the read: ahciIssueCmd() succeeds, returning 0, but PRDC is set to 0, and indeed no data is transferred (The buffer is filled with zeroes, but there by the memset()). PxSERR is set to 0 at this point and PxIS is set to 0x1. This is identical to VirtualBox, except that in VirtualBox, PRDC is 0x8000 but on physical hardware it's 0.

I checked:

* The alignment for all structures is correct.
* The regions are page-aligned, and page-sized (i.e. each is a single page).
* PxSERR is zero.

I don't understand what I'm doing differently between the 2 commands that causes the reads to fail. Can anyone see what I'm doing wrong? I'll continue debugging in the meantime.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Tue Nov 14, 2023 1:23 am 
Offline
Member
Member

Joined: Sat Jul 02, 2016 7:02 am
Posts: 210
perhaps cache-mgmt, if the various buffers used to communicate with the device are cached in the CPU caches?
Or is something optimized away that emulators have a sane default for, but that an actual hw might need?


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Tue Nov 14, 2023 1:45 am 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
As far as i can tell, the CPU is cache-coherent with the PCI bus master on x86_64. Are there any steps your driver takes to manage the cache?

EDIT: I keep forgetting, but i think i also checked this: although for the IDENTIFY command my memory is uncached, there is also another different; after IDENTIFY, PRDC is 0x200, but after the read it is zero; indicating the AHCI controller read zero bytes (despite reporting success), not just that the CPU is reading the wrong data. PRDC itself is uncached.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Tue Nov 14, 2023 4:52 am 
Offline
Member
Member

Joined: Sat Jul 02, 2016 7:02 am
Posts: 210
mariuszp wrote:
As far as i can tell, the CPU is cache-coherent with the PCI bus master on x86_64. Are there any steps your driver takes to manage the cache?

Apologies. You are correct. I mistakenly assumed that it is necessary on all platforms.

What if, instead of IDENTIFY, the transfer cmds are issued as the very first commands?
The IDENTIFY does succeed on h/w, so it can be commented out.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Tue Nov 14, 2023 5:35 am 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
linuxyne wrote:
mariuszp wrote:
As far as i can tell, the CPU is cache-coherent with the PCI bus master on x86_64. Are there any steps your driver takes to manage the cache?

Apologies. You are correct. I mistakenly assumed that it is necessary on all platforms.

What if, instead of IDENTIFY, the transfer cmds are issued as the very first commands?
The IDENTIFY does succeed on h/w, so it can be commented out.


I have tried skipping over the IDENTIFY command spoofing the results like you suggested (note there is exactly one drive connected to the physical AHCI):

Code:
// (ataInit)

   // issue the command and await completion
#if 0
   __sync_synchronize();
   if (ahciIssueCmd(dev->port) != 0)
   {
      kprintf("sdahci: error during identification\n");
      return;
   };
#endif

// ...
   // issue the flush command
#if 0
   int status = ahciIssueCmd(dev->port);
   kprintf("sdahci: cache flush status: %d\n", status);
#endif


After this change, the read still fails in the same way: SERR is zero, PRDC is zero, no data is read.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Tue Nov 14, 2023 10:30 am 
Offline
Member
Member

Joined: Sat Jul 02, 2016 7:02 am
Posts: 210
mariuszp wrote:
After this change, the read still fails in the same way: SERR is zero, PRDC is zero, no data is read.


Hmm, thanks.

I am out of ideas. Perhaps anybody else with more knowledge and experience can chime in.

There's RFIS that you may want to check to see if the hba stored any values in there; PxIS being 1 should mean that RFIS has been stored into the system memory, if it has been setup.

I can create a small app, 32-bit, protected-mode, without mmu, without interrupt-controller, to run on the h/w, by tomorrow, for testing.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Tue Nov 14, 2023 12:02 pm 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
linuxyne wrote:
mariuszp wrote:
After this change, the read still fails in the same way: SERR is zero, PRDC is zero, no data is read.


Hmm, thanks.

I am out of ideas. Perhaps anybody else with more knowledge and experience can chime in.

There's RFIS that you may want to check to see if the hba stored any values in there; PxIS being 1 should mean that RFIS has been stored into the system memory, if it has been setup.

I can create a small app, 32-bit, protected-mode, without mmu, without interrupt-controller, to run on the h/w, by tomorrow, for testing.


Thank you for your help so far and if the app isn't too much of a bother I'll appreciate that greatly too (And I'm sure it'll be useful to others).

In the meantime, I went and got a dump of the received FIS, both in VBox and real hardware.

In VBOX we have:

Attachment:
VirtualBox_Shared Glidix_14_11_2023_17_48_29.png
VirtualBox_Shared Glidix_14_11_2023_17_48_29.png [ 19.05 KiB | Viewed 2602 times ]


Meanwhile on real hardware:

Attachment:
PHYISCAL_HARDWARE_FIS.jpg
PHYISCAL_HARDWARE_FIS.jpg [ 120.43 KiB | Viewed 2602 times ]


I can see a FIS is received but it has some differences to the VBox one. I will analyze it more thoroughly now.

I am a little confused as to why the first 16 bytes are all 0 in the FIS: the fis_type field is at offset 0, and "0x00" does not appear to be a valid value for it (yet both VBox and the hardware show this value). I'll check all the alignment requirements again, although I think I already checked that. Ah, yes, the different FIS types are at different offsets.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Tue Nov 14, 2023 10:05 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
Have you checked whether PIO reads work?

Have you tried QEMU? If your code fails the same way in QEMU, you can use its logging facilities to figure out why.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Wed Nov 15, 2023 2:38 am 
Offline
Member
Member

Joined: Sat Jul 02, 2016 7:02 am
Posts: 210
linuxyne wrote:
I can create a small app, 32-bit, protected-mode, without mmu, without interrupt-controller, to run on the h/w, by tomorrow, for testing.


The app is here. The download and extraction passwords are the same: ahci

A script is included that builds a grub-mkrescue iso.

The code requires matching with the state machine in the AHCI docs, to smooth out the many wrinkles. It also begins by resetting the controller; that and some of the following steps may not be required, if one relies on the setup already performed by the BIOS/hw.

The file ahci.c needs to be adjusted by setting the PCI b/d/f numbers of the controller device and the port number (PIX) of the port where the disk resides.

You may want to try it on an emulator first, before booting your hw machine.

The output when booting the iso, with a 8086:1c02 controller, is as below.
Image

It prints the letter 'J' on detecting prdbc == 0x200 (1 sector).


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Wed Nov 15, 2023 4:12 am 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
Octocontrabass wrote:
Have you checked whether PIO reads work?

Have you tried QEMU? If your code fails the same way in QEMU, you can use its logging facilities to figure out why.


Annoyingly, in QEMU it reports a signature of 0xFFFFFFFF from the port and thus does not detect it as an ATA drive. This seems to be a separate issue :(

I'll do linuxyne's test first before I debug this part.

The joys of coming back to OSDev after ~3 years hahaha


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Wed Nov 15, 2023 4:52 am 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
linuxyne wrote:
linuxyne wrote:
I can create a small app, 32-bit, protected-mode, without mmu, without interrupt-controller, to run on the h/w, by tomorrow, for testing.


The app is here. The download and extraction passwords are the same: ahci

A script is included that builds a grub-mkrescue iso.

The code requires matching with the state machine in the AHCI docs, to smooth out the many wrinkles. It also begins by resetting the controller; that and some of the following steps may not be required, if one relies on the setup already performed by the BIOS/hw.

The file ahci.c needs to be adjusted by setting the PCI b/d/f numbers of the controller device and the port number (PIX) of the port where the disk resides.

You may want to try it on an emulator first, before booting your hw machine.

The output when booting the iso, with a 8086:1c02 controller, is as below.
Image

It prints the letter 'J' on detecting prdbc == 0x200 (1 sector).


I booted your code on my physical machine and got this:

Attachment:
linuxyne-test.png
linuxyne-test.png [ 108.17 KiB | Viewed 2471 times ]


It does not print "E" but I think that's correct.

I see it prints the "J" which seems to indicate that it has read the first sector; correct me if I am wrong.

So it looks like something must be different between your code and mine; I will compare thoroughly.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Wed Nov 15, 2023 8:27 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
mariuszp wrote:
Annoyingly, in QEMU it reports a signature of 0xFFFFFFFF from the port and thus does not detect it as an ATA drive. This seems to be a separate issue :(

What options are you passing to QEMU? Your drives might still be attached to an IDE controller even though you have an AHCI controller.


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Thu Nov 16, 2023 3:03 am 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
Octocontrabass wrote:
mariuszp wrote:
Annoyingly, in QEMU it reports a signature of 0xFFFFFFFF from the port and thus does not detect it as an ATA drive. This seems to be a separate issue :(

What options are you passing to QEMU? Your drives might still be attached to an IDE controller even though you have an AHCI controller.


I use the following command:

Code:
qemu-system-x86_64 -drive id=disk,file=/dev/sda,if=none,format=raw -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0


/dev/sda is correct (I installed Glidix on it).

I see the '-device ide-hd' might be wrong, but according to my google searches so far, that's how people are adding SATA drives to QEMU. Is this the wrong option?


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Thu Nov 16, 2023 6:06 am 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
Here's what I have so far:

* My Command Header is identical to linuxyne's.
* My FIS is identical to linuxyne's
* Clearing IS, PxIS, PxSERR does not help (PxSERR is zero anyway).
* linuxyne's code works, but mine does not (mine reports PRDC=0).

This leads me to think I must be doing something wrong during initialization. I'm still looking.

Here's the code for ahciInit() (which calls ataInit() from above) in case anyone wants to see it:

Code:

static void ahciInit(AHCIController *ctrl)
{
   // map MMIO regs
   ctrl->regs = mapPhysMemory((uint64_t) (ctrl->pcidev->bar[5] & ~0xF), sizeof(AHCIMemoryRegs));
   
   // Don't use the controller if it does not support 64-bit addressing.
   if ((ctrl->regs->cap & CAP_S64A) == 0)
   {
      kprintf("sdahci: AHCI controller does not support 64-bit addressing, skipping.");
      return;
   };

   // take ownership of the device from firmware
   ctrl->regs->bohc |= BOHC_OOS;
   while (ctrl->regs->bohc & BOHC_BOS);
   
   // Make sure bus mastering is enabled.
   pciSetBusMastering(ctrl->pcidev, 1);
   ctrl->numAtaDevices = 0;

   // Perform a HBA reset and enable AHCI mode.
   ctrl->regs->ghc |= GHC_AE | GHC_HR;
   while (ctrl->regs->ghc & GHC_HR);
   
   // Initialize the ports.
   int i;
   for (i=0; i<32; i++)
   {
      if (ctrl->regs->pi & (1 << i))
      {
         ahciStopCmd(&ctrl->regs->ports[i]);
         ctrl->regs->ports[i].cmd |= CMD_SUD | CMD_POD;
         ctrl->regs->ports[i].cmd = (ctrl->regs->ports[i].cmd & ~CMD_ICC_MASK) | CMD_ICC_ACTIVE;

         // If staggered spin-up is supported, spin up the device.
         if (ctrl->regs->cap & CAP_SSS)
         {
            ctrl->regs->ports[i].sctl = (ctrl->regs->ports[i].sctl & ~SCTL_DET_MASK) | SCTL_DET_COMRESET;

            sleep(10);

            ctrl->regs->ports[i].sctl &= ~SCTL_DET_MASK;

            sleep(10);
         };   

         ctrl->regs->ports[i].serr = ~0;
         uint32_t ssts = ctrl->regs->ports[i].ssts;
         
         uint8_t ipm = (ssts >> 8) & 0x0F;
         uint8_t det = ssts & 0x0F;
         
         if (det != SSTS_DET_OK)
         {
            continue;
         };
         
         if (ipm != SSTS_IPM_ACTIVE)
         {
            continue;
         };
         
         uint32_t sig = ctrl->regs->ports[i].sig;
         if (sig == AHCI_SIG_ATA)
         {
            kprintf("sdahci: detected ATA drive on port %d\n", i);
            ataInit(ctrl, i);
         }
         else if (sig == AHCI_SIG_ATAPI)
         {
            kprintf("sdahci: detected ATAPI drive on port %d\n", i);
            atapiInit(ctrl, i);
         }
         else
         {
            kprintf("sdahci: unknown device: signature 0x%08X (port %d)\n", sig, i);
         };
      };
   };
};


Top
 Profile  
 
 Post subject: Re: AHCI controller reports success but reads no data
PostPosted: Thu Nov 16, 2023 8:34 am 
Offline
Member
Member

Joined: Sat Jul 02, 2016 7:02 am
Posts: 210
Some thoughts, pls ignore if not applicable:

Is there any difference in behaviour if you compile your driver with different/least/no optimization levels?
Was a volatile qualifier missing at places that need it?
Is the compiler optimizing away critical pieces of code?

----

As Octocontrabass suggested, it may be of benefit to the test with qemu. If the 0xffffffff sig problem is not with the qemu cmdline, then there could be other problems in the driver that are being exposed by qemu. If the driver isn't working with an emulator, it is likely to not work with the actual hw too.

From the qemu's monitor console, trying to read the PxSIG of the device @ port #0.
Code:
qemu-system-i386 \
-m 1g -cpu IvyBridge \
-no-reboot -no-shutdown -serial mon:stdio \
-device ahci,id=ahci \
-device ide-hd,drive=drive0,bus=ahci.0 \
-drive file=disk.img,if=none,id=drive0,format=raw \
-cdrom ahci.iso \
-trace enable=ahci_* \
-trace enable=pci_cfg_*


Code:
QEMU 8.1.50 monitor - type 'help' for more information
(qemu) info pci
  . . .
  Bus  0, device   4, function 0:
    SATA controller: PCI device 8086:2922
      PCI subsystem 1af4:1100
      IRQ 11, pin A
      BAR4: I/O at 0xc040 [0xc05f].
      BAR5: 32 bit memory at 0xfebf1000 [0xfebf1fff].
      id "ahci"

# Reading PxSIG @ port #0
(qemu) xp/1xw 0xfebf1000+(0x40 + 0x0 * 0x20 + 0x9) * 0x4
00000000febf1124: 0x00000101

# Reading PRDBC after the ahci.iso reads a sector
(qemu) xp/1xw 0xfebf1000 + (0x40 + 0x0 * 0x20 + 0x0) * 0x4
00000000febf1100: 0x00103000 # This is the cmd-header
(qemu) xp/1xw 0x00103000+0x4
00103004: 0x00000200


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], FrankRay78, Majestic-12 [Bot] and 26 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