root/ide.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. idewait
  2. ideinit
  3. idestart
  4. ideintr
  5. iderw

   1 // Simple PIO-based (non-DMA) IDE driver code.
   2 
   3 #include "types.h"
   4 #include "defs.h"
   5 #include "param.h"
   6 #include "memlayout.h"
   7 #include "mmu.h"
   8 #include "proc.h"
   9 #include "x86.h"
  10 #include "traps.h"
  11 #include "spinlock.h"
  12 #include "fs.h"
  13 #include "buf.h"
  14 
  15 #define SECTOR_SIZE   512
  16 #define IDE_BSY       0x80
  17 #define IDE_DRDY      0x40
  18 #define IDE_DF        0x20
  19 #define IDE_ERR       0x01
  20 
  21 #define IDE_CMD_READ  0x20
  22 #define IDE_CMD_WRITE 0x30
  23 
  24 // idequeue points to the buf now being read/written to the disk.
  25 // idequeue->qnext points to the next buf to be processed.
  26 // You must hold idelock while manipulating queue.
  27 
  28 static struct spinlock idelock;
  29 static struct buf *idequeue;
  30 
  31 static int havedisk1;
  32 static void idestart(struct buf*);
  33 
  34 // Wait for IDE disk to become ready.
  35 static int
  36 idewait(int checkerr)
  37 {
  38   int r;
  39 
  40   while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) 
  41     ;
  42   if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0)
  43     return -1;
  44   return 0;
  45 }
  46 
  47 void
  48 ideinit(void)
  49 {
  50   int i;
  51   
  52   initlock(&idelock, "ide");
  53   picenable(IRQ_IDE);
  54   ioapicenable(IRQ_IDE, ncpu - 1);
  55   idewait(0);
  56   
  57   // Check if disk 1 is present
  58   outb(0x1f6, 0xe0 | (1<<4));
  59   for(i=0; i<1000; i++){
  60     if(inb(0x1f7) != 0){
  61       havedisk1 = 1;
  62       break;
  63     }
  64   }
  65   
  66   // Switch back to disk 0.
  67   outb(0x1f6, 0xe0 | (0<<4));
  68 }
  69 
  70 // Start the request for b.  Caller must hold idelock.
  71 static void
  72 idestart(struct buf *b)
  73 {
  74   if(b == 0)
  75     panic("idestart");
  76   if(b->blockno >= FSSIZE)
  77     panic("incorrect blockno");
  78   int sector_per_block =  BSIZE/SECTOR_SIZE;
  79   int sector = b->blockno * sector_per_block;
  80 
  81   if (sector_per_block > 7) panic("idestart");
  82   
  83   idewait(0);
  84   outb(0x3f6, 0);  // generate interrupt
  85   outb(0x1f2, sector_per_block);  // number of sectors
  86   outb(0x1f3, sector & 0xff);
  87   outb(0x1f4, (sector >> 8) & 0xff);
  88   outb(0x1f5, (sector >> 16) & 0xff);
  89   outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((sector>>24)&0x0f));
  90   if(b->flags & B_DIRTY){
  91     outb(0x1f7, IDE_CMD_WRITE);
  92     outsl(0x1f0, b->data, BSIZE/4);
  93   } else {
  94     outb(0x1f7, IDE_CMD_READ);
  95   }
  96 }
  97 
  98 // Interrupt handler.
  99 void
 100 ideintr(void)
 101 {
 102   struct buf *b;
 103 
 104   // First queued buffer is the active request.
 105   acquire(&idelock);
 106   if((b = idequeue) == 0){
 107     release(&idelock);
 108     // cprintf("spurious IDE interrupt\n");
 109     return;
 110   }
 111   idequeue = b->qnext;
 112 
 113   // Read data if needed.
 114   if(!(b->flags & B_DIRTY) && idewait(1) >= 0)
 115     insl(0x1f0, b->data, BSIZE/4);
 116   
 117   // Wake process waiting for this buf.
 118   b->flags |= B_VALID;
 119   b->flags &= ~B_DIRTY;
 120   wakeup(b);
 121   
 122   // Start disk on next buf in queue.
 123   if(idequeue != 0)
 124     idestart(idequeue);
 125 
 126   release(&idelock);
 127 }
 128 
 129 //PAGEBREAK!
 130 // Sync buf with disk. 
 131 // If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
 132 // Else if B_VALID is not set, read buf from disk, set B_VALID.
 133 void
 134 iderw(struct buf *b)
 135 {
 136   struct buf **pp;
 137 
 138   if(!(b->flags & B_BUSY))
 139     panic("iderw: buf not busy");
 140   if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
 141     panic("iderw: nothing to do");
 142   if(b->dev != 0 && !havedisk1)
 143     panic("iderw: ide disk 1 not present");
 144 
 145   acquire(&idelock);  //DOC:acquire-lock
 146 
 147   // Append b to idequeue.
 148   b->qnext = 0;
 149   for(pp=&idequeue; *pp; pp=&(*pp)->qnext)  //DOC:insert-queue
 150     ;
 151   *pp = b;
 152   
 153   // Start disk if necessary.
 154   if(idequeue == b)
 155     idestart(b);
 156   
 157   // Wait for request to finish.
 158   while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
 159     sleep(b, &idelock);
 160   }
 161 
 162   release(&idelock);
 163 }

/* [<][>][^][v][top][bottom][index][help] */