00001
00002
00003 #include "types.h"
00004 #include "defs.h"
00005 #include "param.h"
00006 #include "mmu.h"
00007 #include "proc.h"
00008 #include "x86.h"
00009 #include "traps.h"
00010 #include "spinlock.h"
00011 #include "buf.h"
00012
00013 #define IDE_BSY 0x80
00014 #define IDE_DRDY 0x40
00015 #define IDE_DF 0x20
00016 #define IDE_ERR 0x01
00017
00018 #define IDE_CMD_READ 0x20
00019 #define IDE_CMD_WRITE 0x30
00020
00021
00022
00023
00024
00025 static struct spinlock idelock;
00026 static struct buf *idequeue;
00027
00028 static int havedisk1;
00029 static void idestart(struct buf*);
00030
00031
00032 static int
00033 idewait(int checkerr)
00034 {
00035 int r;
00036
00037 while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY)
00038 ;
00039 if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0)
00040 return -1;
00041 return 0;
00042 }
00043
00044 void
00045 ideinit(void)
00046 {
00047 int i;
00048
00049 initlock(&idelock, "ide");
00050 picenable(IRQ_IDE);
00051 ioapicenable(IRQ_IDE, ncpu - 1);
00052 idewait(0);
00053
00054
00055 outb(0x1f6, 0xe0 | (1<<4));
00056 for(i=0; i<1000; i++){
00057 if(inb(0x1f7) != 0){
00058 havedisk1 = 1;
00059 break;
00060 }
00061 }
00062
00063
00064 outb(0x1f6, 0xe0 | (0<<4));
00065 }
00066
00067
00068 static void
00069 idestart(struct buf *b)
00070 {
00071 if(b == 0)
00072 panic("idestart");
00073
00074 idewait(0);
00075 outb(0x3f6, 0);
00076 outb(0x1f2, 1);
00077 outb(0x1f3, b->sector & 0xff);
00078 outb(0x1f4, (b->sector >> 8) & 0xff);
00079 outb(0x1f5, (b->sector >> 16) & 0xff);
00080 outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((b->sector>>24)&0x0f));
00081 if(b->flags & B_DIRTY){
00082 outb(0x1f7, IDE_CMD_WRITE);
00083 outsl(0x1f0, b->data, 512/4);
00084 } else {
00085 outb(0x1f7, IDE_CMD_READ);
00086 }
00087 }
00088
00089
00090 void
00091 ideintr(void)
00092 {
00093 struct buf *b;
00094
00095
00096 acquire(&idelock);
00097 if((b = idequeue) == 0){
00098 release(&idelock);
00099 cprintf("Spurious IDE interrupt.\n");
00100 return;
00101 }
00102 idequeue = b->qnext;
00103
00104
00105 if(!(b->flags & B_DIRTY) && idewait(1) >= 0)
00106 insl(0x1f0, b->data, 512/4);
00107
00108
00109 b->flags |= B_VALID;
00110 b->flags &= ~B_DIRTY;
00111 wakeup(b);
00112
00113
00114 if(idequeue != 0)
00115 idestart(idequeue);
00116
00117 release(&idelock);
00118 }
00119
00120
00121
00122
00123 void
00124 iderw(struct buf *b)
00125 {
00126 struct buf **pp;
00127
00128 if(!(b->flags & B_BUSY))
00129 panic("iderw: buf not busy");
00130 if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
00131 panic("iderw: nothing to do");
00132 if(b->dev != 0 && !havedisk1)
00133 panic("idrw: ide disk 1 not present");
00134
00135 acquire(&idelock);
00136
00137
00138 b->qnext = 0;
00139 for(pp=&idequeue; *pp; pp=&(*pp)->qnext)
00140 ;
00141 *pp = b;
00142
00143
00144 if(idequeue == b)
00145 idestart(b);
00146
00147
00148
00149 while((b->flags & (B_VALID|B_DIRTY)) != B_VALID)
00150 sleep(b, &idelock);
00151
00152 release(&idelock);
00153 }