root/ide.c

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

/* [previous][next][first][last][top][bottom][index][help]  */