1f5527388Srsc // Simple PIO-based (non-DMA) IDE driver code.
2ae6e8aa7Srtm
3ae6e8aa7Srtm #include "types.h"
4558ab49fSrsc #include "defs.h"
5ae6e8aa7Srtm #include "param.h"
69aa0337dSFrans Kaashoek #include "memlayout.h"
7ae6e8aa7Srtm #include "mmu.h"
8ae6e8aa7Srtm #include "proc.h"
9ae6e8aa7Srtm #include "x86.h"
107abf49d2Skaashoek #include "traps.h"
110dd42537Srsc #include "spinlock.h"
126670d3b5SFrans Kaashoek #include "sleeplock.h"
13c24ac5d7SFrans Kaashoek #include "fs.h"
14902b13f5Srtm #include "buf.h"
15ae6e8aa7Srtm
16c24ac5d7SFrans Kaashoek #define SECTOR_SIZE 512
17ae6e8aa7Srtm #define IDE_BSY 0x80
18ae6e8aa7Srtm #define IDE_DRDY 0x40
19ae6e8aa7Srtm #define IDE_DF 0x20
20ae6e8aa7Srtm #define IDE_ERR 0x01
21ae6e8aa7Srtm
2296d467b3Srsc #define IDE_CMD_READ 0x20
2396d467b3Srsc #define IDE_CMD_WRITE 0x30
244a3576b8SFrans Kaashoek #define IDE_CMD_RDMUL 0xc4
254a3576b8SFrans Kaashoek #define IDE_CMD_WRMUL 0xc5
2696d467b3Srsc
27c47bc4fdSrsc // idequeue points to the buf now being read/written to the disk.
28c47bc4fdSrsc // idequeue->qnext points to the next buf to be processed.
29c47bc4fdSrsc // You must hold idelock while manipulating queue.
30bb207a1dSrsc
31c47bc4fdSrsc static struct spinlock idelock;
32c47bc4fdSrsc static struct buf *idequeue;
33bb207a1dSrsc
34c47bc4fdSrsc static int havedisk1;
3521575761Srsc static void idestart(struct buf*);
362aa4c3bcSrtm
3719297cafSrsc // Wait for IDE disk to become ready.
38ae6e8aa7Srtm static int
idewait(int checkerr)3934295f46Srsc idewait(int checkerr)
40ae6e8aa7Srtm {
41ae6e8aa7Srtm int r;
42ae6e8aa7Srtm
43c47bc4fdSrsc while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY)
44f5527388Srsc ;
4534295f46Srsc if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0)
46ae6e8aa7Srtm return -1;
47ae6e8aa7Srtm return 0;
48ae6e8aa7Srtm }
49ae6e8aa7Srtm
50b22d8982Skaashoek void
ideinit(void)5121575761Srsc ideinit(void)
52b22d8982Skaashoek {
53d7b44dbcSrsc int i;
54d7b44dbcSrsc
55c47bc4fdSrsc initlock(&idelock, "ide");
5621575761Srsc ioapicenable(IRQ_IDE, ncpu - 1);
5721575761Srsc idewait(0);
58d7b44dbcSrsc
59d7b44dbcSrsc // Check if disk 1 is present
60c1b100e9Srsc outb(0x1f6, 0xe0 | (1<<4));
61d7b44dbcSrsc for(i=0; i<1000; i++){
62d7b44dbcSrsc if(inb(0x1f7) != 0){
63c47bc4fdSrsc havedisk1 = 1;
64d7b44dbcSrsc break;
65d7b44dbcSrsc }
66b22d8982Skaashoek }
67b22d8982Skaashoek
68d7b44dbcSrsc // Switch back to disk 0.
69c1b100e9Srsc outb(0x1f6, 0xe0 | (0<<4));
70d7b44dbcSrsc }
71d7b44dbcSrsc
72c47bc4fdSrsc // Start the request for b. Caller must hold idelock.
73d7b44dbcSrsc static void
idestart(struct buf * b)7421575761Srsc idestart(struct buf *b)
75ae6e8aa7Srtm {
76d7b44dbcSrsc if(b == 0)
7721575761Srsc panic("idestart");
78895af77fSFrans Kaashoek if(b->blockno >= FSSIZE)
79895af77fSFrans Kaashoek panic("incorrect blockno");
80c24ac5d7SFrans Kaashoek int sector_per_block = BSIZE/SECTOR_SIZE;
81c24ac5d7SFrans Kaashoek int sector = b->blockno * sector_per_block;
824a3576b8SFrans Kaashoek int read_cmd = (sector_per_block == 1) ? IDE_CMD_READ : IDE_CMD_RDMUL;
834a3576b8SFrans Kaashoek int write_cmd = (sector_per_block == 1) ? IDE_CMD_WRITE : IDE_CMD_WRMUL;
84c24ac5d7SFrans Kaashoek
85c24ac5d7SFrans Kaashoek if (sector_per_block > 7) panic("idestart");
86ae6e8aa7Srtm
8721575761Srsc idewait(0);
88d7b44dbcSrsc outb(0x3f6, 0); // generate interrupt
89c24ac5d7SFrans Kaashoek outb(0x1f2, sector_per_block); // number of sectors
90c24ac5d7SFrans Kaashoek outb(0x1f3, sector & 0xff);
91c24ac5d7SFrans Kaashoek outb(0x1f4, (sector >> 8) & 0xff);
92c24ac5d7SFrans Kaashoek outb(0x1f5, (sector >> 16) & 0xff);
93c24ac5d7SFrans Kaashoek outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((sector>>24)&0x0f));
94d003d232Srsc if(b->flags & B_DIRTY){
954a3576b8SFrans Kaashoek outb(0x1f7, write_cmd);
96c24ac5d7SFrans Kaashoek outsl(0x1f0, b->data, BSIZE/4);
97d7b44dbcSrsc } else {
984a3576b8SFrans Kaashoek outb(0x1f7, read_cmd);
99d7b44dbcSrsc }
100ae6e8aa7Srtm }
101ae6e8aa7Srtm
102d7b44dbcSrsc // Interrupt handler.
10350f88503Srsc void
ideintr(void)10421575761Srsc ideintr(void)
10550f88503Srsc {
106d7b44dbcSrsc struct buf *b;
107d7b44dbcSrsc
108a5fbfe41SRobert Morris // First queued buffer is the active request.
109c47bc4fdSrsc acquire(&idelock);
110*abf847a0SFrans Kaashoek
111c47bc4fdSrsc if((b = idequeue) == 0){
112c47bc4fdSrsc release(&idelock);
113d7b44dbcSrsc return;
114902b13f5Srtm }
115c47bc4fdSrsc idequeue = b->qnext;
116d7b44dbcSrsc
117d7b44dbcSrsc // Read data if needed.
11821575761Srsc if(!(b->flags & B_DIRTY) && idewait(1) >= 0)
119c24ac5d7SFrans Kaashoek insl(0x1f0, b->data, BSIZE/4);
120d7b44dbcSrsc
121d7b44dbcSrsc // Wake process waiting for this buf.
122d003d232Srsc b->flags |= B_VALID;
123d003d232Srsc b->flags &= ~B_DIRTY;
124d7b44dbcSrsc wakeup(b);
125d7b44dbcSrsc
126d7b44dbcSrsc // Start disk on next buf in queue.
127c47bc4fdSrsc if(idequeue != 0)
128c47bc4fdSrsc idestart(idequeue);
129d7b44dbcSrsc
130c47bc4fdSrsc release(&idelock);
13150f88503Srsc }
13250f88503Srsc
133d7b44dbcSrsc //PAGEBREAK!
134d003d232Srsc // Sync buf with disk.
135d003d232Srsc // If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
136d003d232Srsc // Else if B_VALID is not set, read buf from disk, set B_VALID.
13719297cafSrsc void
iderw(struct buf * b)13821575761Srsc iderw(struct buf *b)
139ae6e8aa7Srtm {
140902b13f5Srtm struct buf **pp;
1418ec6530fSkaashoek
1426670d3b5SFrans Kaashoek if(!holdingsleep(&b->lock))
1436670d3b5SFrans Kaashoek panic("iderw: buf not locked");
144d003d232Srsc if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
14521575761Srsc panic("iderw: nothing to do");
146c47bc4fdSrsc if(b->dev != 0 && !havedisk1)
1471a81e38bSRuss Cox panic("iderw: ide disk 1 not present");
148ae6e8aa7Srtm
1498a9b6dbdSFrans Kaashoek acquire(&idelock); //DOC:acquire-lock
15019297cafSrsc
151c47bc4fdSrsc // Append b to idequeue.
152902b13f5Srtm b->qnext = 0;
1538a9b6dbdSFrans Kaashoek for(pp=&idequeue; *pp; pp=&(*pp)->qnext) //DOC:insert-queue
154d7b44dbcSrsc ;
155902b13f5Srtm *pp = b;
156902b13f5Srtm
157d7b44dbcSrsc // Start disk if necessary.
158c47bc4fdSrsc if(idequeue == b)
15921575761Srsc idestart(b);
16011a9947fSrtm
161d7b44dbcSrsc // Wait for request to finish.
16240889627SFrans Kaashoek while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
163c47bc4fdSrsc sleep(b, &idelock);
16440889627SFrans Kaashoek }
165d003d232Srsc
166*abf847a0SFrans Kaashoek
167c47bc4fdSrsc release(&idelock);
168ae6e8aa7Srtm }
169