/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- idewait
- ideinit
- idestart
- ideintr
- 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 }