no interrupt when reading from drive

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

no interrupt when reading from drive

Post by sancho1980 »

hi
i am trying to read one sector from my (already detected by "identify") drive, but i am not getting any interrupts.
what i do is the following:

Code: Select all

static void read_sector(uint32_t number, channel_t *channel, err_t *error)
{
#define PORT_DATA 0x0
#define PORT_ERROR 0x1
#define PORT_SECTORCOUNT 0x2
#define PORT_LBA_LOW 0x3
#define PORT_LBA_MID 0x4
#define PORT_LBA_HIGH 0x5
#define PORT_DRIVESELECT 0x6
#define PORT_HEADSELECT PORT_DRIVESELECT
#define PORT_COMMAND 0x7

#define PORT_STATUS PORT_COMMAND

#define COMMAND_IDENTIFY 0xec
#define COMMAND_READSECTORS 0x20

#define BIT_ERR 0x1

#define BIT_DRQ 0x8

#define BIT_BUSY 0x80


#define PORTBASE_PRIMARY 0x1f0
#define PORTBASE_SECONDARY 0x170

...

static void select_drive(boolean_t master, boolean_t primary, err_t *error)
{
  uint32_t value = 0;
  uint32_t port_base = 0;

  if (master) {
    value = 0xa0;
  } else {
    value = 0xb0;
  }
  if (primary) {
    port_base = PORTBASE_PRIMARY;
  } else {
    port_base = PORTBASE_SECONDARY;
  }
  
  terror(call_syscall_outb(port_base | PORT_DRIVESELECT, value, error))

finish:
  return;
}

...

static void read_sector(uint32_t number, channel_t *channel, err_t *error)
{
  uint32_t i = 0;
  uint32_t bytes = 0;
  uint32_t port_base = 0;
  boolean_t master = ((channel->bus_info & BUSINFO_MASTER) != 0);
  boolean_t primary = ((channel->bus_info & BUSINFO_PRIMARY) != 0);
  uint8_t value = 0;
  uint32_t irq_expected = 0;
  if (number >= channel->lba_sectors) {
    //TODO: set error...
  }
  //TODO: check if drive is present (and maybe type)
  terror(select_drive(master, primary, error))

  if (master) {
    value = 0xe0;
  } else {
    value = 0xf0;
  }
  if (primary) {
    port_base = PORTBASE_PRIMARY;
  } else {
    port_base = PORTBASE_SECONDARY;
  }
  terror(call_syscall_outb(port_base | PORT_DRIVESELECT, (value | (number >> 24)), error))
  //can be left out
  //terror(call_syscall_outb(port_base | PORT_ERROR, 0))
  //read one sector
  terror(call_syscall_outb(port_base | PORT_SECTORCOUNT, 1, error))
  terror(call_syscall_outb(port_base | PORT_LBA_LOW, (number & 0xff), error))
  terror(call_syscall_outb(port_base | PORT_LBA_MID, ((number >> 8) & 0xff), error))
  terror(call_syscall_outb(port_base | PORT_LBA_HIGH, ((number >> 16) & 0xff), error))
  terror(call_syscall_outb(port_base | PORT_COMMAND, COMMAND_READSECTORS, error))
  irq_expected = primary ? 14 : 15;
  for(;;) {
    terror(bytes = call_syscall_receive(ANYPROC, NULL, 0, error))
    if ((*error) == irq_expected) {
      break;
    }
  }
  for (i = 0; i < 256; i++) {
    terror(buffer[i] = call_syscall_inw(port_base | PORT_DATA, error))
  }
  //wait 400 ns
finish:
  return;
}
Just in case you wonder, "terror()" is just a convenience macro (Test Error) I use throughout my user space programs:

Code: Select all

#define hasFailed(x) (x < OK)

#define terror(x) \
  x; \
  if (hasFailed((*error))) { \
    goto finish; \
  }
For the rest in case you wonder, I "ask" for interrupts from my user space programs (my hd driver is a user space program because this is a micro-kernel) by calling call_syscall_receive(). If the value returned in *error is positive, then this means the interrupt with number *error has occured.
IRQs and ports have to be claimed by user space programs beforehand (which I also do).
So just to clarify that I don't think anything with my port-IRQ handling mechanism is going wrong per se (I use it successfully in my tty driver).
Also, I put some debugging code in my kernel just to make sure there really is no interrupt from the hard drive.
What I found out is that my code never returns from call_syscall_receive() (no interrupt occurs after sending the sector read command). The system itself doesn't hang. My tty continues to work and react to user input. Could you have a look particularly at how I send the sector read command to the drive and see if I'm missing something here?

Thanks
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Re: no interrupt when reading from drive

Post by sancho1980 »

i check the status port immediately before and after sending the read command and it turns out that the drq bit is unset immediately before and set immediately after (im using bochs emulation), so the read command by itself seems to work, but why am i not getting an interrupt? i dont want to use polling...
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: no interrupt when reading from drive

Post by bewing »

When you "check the status port immediately after sending the read command", what code are you using to do that?
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Re: no interrupt when reading from drive

Post by sancho1980 »

no code at all, i just read from the status port:

http://code.google.com/p/mycrokernel/so ... /hd/main.c (line 378, r71)
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: no interrupt when reading from drive

Post by bewing »

OK, then let me say this another way. There is a difference between the regular Status Port and the Alternate Status port, and you should probably read this: http://wiki.osdev.org/ATA_PIO_Mode#Pree ... rom_firing:
very carefully.
sancho1980
Member
Member
Posts: 199
Joined: Fri Jul 13, 2007 6:37 am
Location: Stuttgart/Germany
Contact:

Re: no interrupt when reading from drive

Post by sancho1980 »

I think you are referring to the difference between alternate and regular status port with your post, but i'd read that already
i think you got me wrong here anyway: when i say i read the status after issuing the command, i did so only AFTER i learnt i wouldnt get any interrupt
might it be that bochs simply doesnt cause an interrupt for my drive read just because the data are ready pretty much "immediately"??
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: no interrupt when reading from drive

Post by bewing »

Yes, bochs triggers the IRQ almost immediately. Your code should already be expecting the IRQ before you send the "read" command.
Post Reply