xref: /xv6-public/ide.c (revision 4f14d8d1)
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