* more re-work
[mascara-docs.git] / i386 / junos / MIT / src.xv6 / ide.c
blob7946f94104b2ddd7e5fa6f50cc8839a690ae1ae1
1 // Simple PIO-based (non-DMA) IDE driver code.
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 "buf.h"
14 #define IDE_BSY 0x80
15 #define IDE_DRDY 0x40
16 #define IDE_DF 0x20
17 #define IDE_ERR 0x01
19 #define IDE_CMD_READ 0x20
20 #define IDE_CMD_WRITE 0x30
22 // idequeue points to the buf now being read/written to the disk.
23 // idequeue->qnext points to the next buf to be processed.
24 // You must hold idelock while manipulating queue.
26 static struct spinlock idelock;
27 static struct buf *idequeue;
29 static int havedisk1;
30 static void idestart(struct buf*);
32 // Wait for IDE disk to become ready.
33 static int
34 idewait(int checkerr)
36 int r;
38 while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY)
40 if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0)
41 return -1;
42 return 0;
45 void
46 ideinit(void)
48 int i;
50 initlock(&idelock, "ide");
51 picenable(IRQ_IDE);
52 ioapicenable(IRQ_IDE, ncpu - 1);
53 idewait(0);
55 // Check if disk 1 is present
56 outb(0x1f6, 0xe0 | (1<<4));
57 for(i=0; i<1000; i++){
58 if(inb(0x1f7) != 0){
59 havedisk1 = 1;
60 break;
64 // Switch back to disk 0.
65 outb(0x1f6, 0xe0 | (0<<4));
68 // Start the request for b. Caller must hold idelock.
69 static void
70 idestart(struct buf *b)
72 if(b == 0)
73 panic("idestart");
75 idewait(0);
76 outb(0x3f6, 0); // generate interrupt
77 outb(0x1f2, 1); // number of sectors
78 outb(0x1f3, b->sector & 0xff);
79 outb(0x1f4, (b->sector >> 8) & 0xff);
80 outb(0x1f5, (b->sector >> 16) & 0xff);
81 outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((b->sector>>24)&0x0f));
82 if(b->flags & B_DIRTY){
83 outb(0x1f7, IDE_CMD_WRITE);
84 outsl(0x1f0, b->data, 512/4);
85 } else {
86 outb(0x1f7, IDE_CMD_READ);
90 // Interrupt handler.
91 void
92 ideintr(void)
94 struct buf *b;
96 // First queued buffer is the active request.
97 acquire(&idelock);
98 if((b = idequeue) == 0){
99 release(&idelock);
100 // cprintf("spurious IDE interrupt\n");
101 return;
103 idequeue = b->qnext;
105 // Read data if needed.
106 if(!(b->flags & B_DIRTY) && idewait(1) >= 0)
107 insl(0x1f0, b->data, 512/4);
109 // Wake process waiting for this buf.
110 b->flags |= B_VALID;
111 b->flags &= ~B_DIRTY;
112 wakeup(b);
114 // Start disk on next buf in queue.
115 if(idequeue != 0)
116 idestart(idequeue);
118 release(&idelock);
121 //PAGEBREAK!
122 // Sync buf with disk.
123 // If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
124 // Else if B_VALID is not set, read buf from disk, set B_VALID.
125 void
126 iderw(struct buf *b)
128 struct buf **pp;
130 if(!(b->flags & B_BUSY))
131 panic("iderw: buf not busy");
132 if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
133 panic("iderw: nothing to do");
134 if(b->dev != 0 && !havedisk1)
135 panic("iderw: ide disk 1 not present");
137 acquire(&idelock); //DOC: acquire-lock
139 // Append b to idequeue.
140 b->qnext = 0;
141 for(pp=&idequeue; *pp; pp=&(*pp)->qnext) //DOC: insert-queue
143 *pp = b;
145 // Start disk if necessary.
146 if(idequeue == b)
147 idestart(b);
149 // Wait for request to finish.
150 while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
151 sleep(b, &idelock);
154 release(&idelock);