diff options
| -rw-r--r-- | ide.c | 130 | 
1 files changed, 62 insertions, 68 deletions
@@ -26,20 +26,16 @@ static struct spinlock ide_lock;  static struct buf *ide_queue;  static int disk_1_present; - -static int ide_probe_disk1(void);  static void ide_start_request(); -//PAGEBREAK: 10  // Wait for IDE disk to become ready.  static int  ide_wait_ready(int check_error)  {    int r; -  while(((r = inb(0x1F7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) +  while(((r = inb(0x1f7)) & IDE_BSY) || !(r & IDE_DRDY))      ; -    if(check_error && (r & (IDE_DF|IDE_ERR)) != 0)      return -1;    return 0; @@ -48,105 +44,103 @@ ide_wait_ready(int check_error)  void  ide_init(void)  { +  int i; +    initlock(&ide_lock, "ide");    irq_enable(IRQ_IDE);    ioapic_enable(IRQ_IDE, ncpu - 1);    ide_wait_ready(0); -  disk_1_present = ide_probe_disk1(); +   +  // Check if disk 1 is present +  outb(0x1f6, 0xE0 | (1<<4)); +  for(i=0; i<1000; i++){ +    if(inb(0x1f7) != 0){ +      disk_1_present = 1; +      break; +    } +  } +   +  // Switch back to disk 0. +  outb(0x1f6, 0xE0 | (0<<4));  } -// Probe to see if disk 1 exists (we assume disk 0 exists). -static int -ide_probe_disk1(void) +// Start the request for b.  Caller must hold ide_lock. +static void +ide_start_request(struct buf *b)  { -  int r, x; +  if(b == 0) +    panic("ide_start_request"); -  // wait for Device 0 to be ready    ide_wait_ready(0); - -  // switch to Device 1 -  outb(0x1F6, 0xE0 | (1<<4)); - -  // check for Device 1 to be ready for a while -  for(x = 0; x < 1000 && (r = inb(0x1F7)) == 0; x++) -    ; - -  // switch back to Device 0 -  outb(0x1F6, 0xE0 | (0<<4)); - -  return x < 1000; +  outb(0x3f6, 0);  // generate interrupt +  outb(0x1f2, 1);  // number of sectors +  outb(0x1f3, b->sector & 0xff); +  outb(0x1f4, (b->sector >> 8) & 0xff); +  outb(0x1f5, (b->sector >> 16) & 0xff); +  outb(0x1f6, 0xE0 | ((b->dev&1)<<4) | ((b->sector>>24)&0x0f)); +  if(b->flags & B_WRITE){ +    outb(0x1f7, IDE_CMD_WRITE); +    outsl(0x1f0, b->data, 512/4); +  }else{ +    outb(0x1f7, IDE_CMD_READ); +  }  } -// Interrupt handler - wake up the request that just finished. +// Interrupt handler.  void  ide_intr(void)  { +  struct buf *b; +    acquire(&ide_lock); -  if(ide_queue){ -    if((ide_queue->flags & B_WRITE) == 0) -      if(ide_wait_ready(1) >= 0) -        insl(0x1F0, ide_queue->data, 512/4); -    ide_queue->done = 1; -    wakeup(ide_queue); -    ide_queue = ide_queue->qnext; -    ide_start_request(); -  } else { +  if((b = ide_queue) == 0){      cprintf("stray ide interrupt\n"); +    release(&ide_lock); +    return;    } -  release(&ide_lock); -} -// Start the next request in the queue. -// Caller must hold ide_lock. -static void -ide_start_request (void) -{ -  if(ide_queue){ -    ide_wait_ready(0); -    outb(0x3f6, 0);  // generate interrupt -    outb(0x1F2, 1);  // number of sectors -    outb(0x1F3, ide_queue->sector & 0xFF); -    outb(0x1F4, (ide_queue->sector >> 8) & 0xFF); -    outb(0x1F5, (ide_queue->sector >> 16) & 0xFF); -    outb(0x1F6, 0xE0 | -         ((ide_queue->dev & 1)<<4) | -         ((ide_queue->sector>>24)&0x0F)); -    if(ide_queue->flags & B_WRITE){ -      outb(0x1F7, IDE_CMD_WRITE); -      outsl(0x1F0, ide_queue->data, 512/4); -    } else { -      outb(0x1F7, IDE_CMD_READ); -    } -  } +  // Read data if needed. +  if((b->flags & B_WRITE) == 0 && ide_wait_ready(1) >= 0) +    insl(0x1f0, b->data, 512/4); +   +  // Wake process waiting for this buf. +  b->done = 1; +  wakeup(b); +   +  // Start disk on next buf in queue. +  if((ide_queue = b->qnext) != 0) +    ide_start_request(ide_queue); + +  release(&ide_lock);  } -//PAGEBREAK: 30 -// Queue up a disk operation and wait for it to finish. -// b must have B_BUSY set. +//PAGEBREAK! +// Queue a disk operation and wait for it to finish.  void  ide_rw(struct buf *b)  {    struct buf **pp; -  if((b->dev & 0xff) && !disk_1_present) +  if(!(b->flags & B_BUSY)) +    panic("ide_rw: buf not busy"); +  if(b->dev != 0 && !disk_1_present)      panic("ide disk 1 not present");    acquire(&ide_lock); +  // Append b to ide_queue.    b->done = 0;    b->qnext = 0; - -  // append b to ide_queue -  pp = &ide_queue; -  while(*pp) -    pp = &(*pp)->qnext; +  for(pp=&ide_queue; *pp; pp=&(*pp)->qnext) +    ;    *pp = b; +  // Start disk if necessary.    if(ide_queue == b) -    ide_start_request(); +    ide_start_request(b); +  // Wait for request to finish.    while(!b->done)      sleep(b, &ide_lock); -      release(&ide_lock);  }  | 
