diff --git a/ide.c b/ide.c index 3b3b808db8..83bffcf2b8 100644 --- a/ide.c +++ b/ide.c @@ -26,20 +26,16 @@ static struct spinlock ide_lock; static struct buf *ide_queue; static int disk_1_present; - -static int ide_probe_disk1(void); static void ide_start_request(); -//PAGEBREAK: 10 // Wait for IDE disk to become ready. static int ide_wait_ready(int check_error) { int r; - while(((r = inb(0x1F7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) + while(((r = inb(0x1f7)) & IDE_BSY) || !(r & IDE_DRDY)) ; - if(check_error && (r & (IDE_DF|IDE_ERR)) != 0) return -1; return 0; @@ -48,105 +44,103 @@ ide_wait_ready(int check_error) void ide_init(void) { + int i; + initlock(&ide_lock, "ide"); irq_enable(IRQ_IDE); ioapic_enable(IRQ_IDE, ncpu - 1); ide_wait_ready(0); - disk_1_present = ide_probe_disk1(); + + // Check if disk 1 is present + outb(0x1f6, 0xE0 | (1<<4)); + for(i=0; i<1000; i++){ + if(inb(0x1f7) != 0){ + disk_1_present = 1; + break; + } + } + + // Switch back to disk 0. + outb(0x1f6, 0xE0 | (0<<4)); } -// Probe to see if disk 1 exists (we assume disk 0 exists). -static int -ide_probe_disk1(void) +// Start the request for b. Caller must hold ide_lock. +static void +ide_start_request(struct buf *b) { - int r, x; + if(b == 0) + panic("ide_start_request"); - // wait for Device 0 to be ready ide_wait_ready(0); - - // switch to Device 1 - outb(0x1F6, 0xE0 | (1<<4)); - - // check for Device 1 to be ready for a while - for(x = 0; x < 1000 && (r = inb(0x1F7)) == 0; x++) - ; - - // switch back to Device 0 - outb(0x1F6, 0xE0 | (0<<4)); - - return x < 1000; + outb(0x3f6, 0); // generate interrupt + outb(0x1f2, 1); // number of sectors + outb(0x1f3, b->sector & 0xff); + outb(0x1f4, (b->sector >> 8) & 0xff); + outb(0x1f5, (b->sector >> 16) & 0xff); + outb(0x1f6, 0xE0 | ((b->dev&1)<<4) | ((b->sector>>24)&0x0f)); + if(b->flags & B_WRITE){ + outb(0x1f7, IDE_CMD_WRITE); + outsl(0x1f0, b->data, 512/4); + }else{ + outb(0x1f7, IDE_CMD_READ); + } } -// Interrupt handler - wake up the request that just finished. +// Interrupt handler. void ide_intr(void) { + struct buf *b; + acquire(&ide_lock); - if(ide_queue){ - if((ide_queue->flags & B_WRITE) == 0) - if(ide_wait_ready(1) >= 0) - insl(0x1F0, ide_queue->data, 512/4); - ide_queue->done = 1; - wakeup(ide_queue); - ide_queue = ide_queue->qnext; - ide_start_request(); - } else { + if((b = ide_queue) == 0){ cprintf("stray ide interrupt\n"); + release(&ide_lock); + return; } - release(&ide_lock); -} -// Start the next request in the queue. -// Caller must hold ide_lock. -static void -ide_start_request (void) -{ - if(ide_queue){ - ide_wait_ready(0); - outb(0x3f6, 0); // generate interrupt - outb(0x1F2, 1); // number of sectors - outb(0x1F3, ide_queue->sector & 0xFF); - outb(0x1F4, (ide_queue->sector >> 8) & 0xFF); - outb(0x1F5, (ide_queue->sector >> 16) & 0xFF); - outb(0x1F6, 0xE0 | - ((ide_queue->dev & 1)<<4) | - ((ide_queue->sector>>24)&0x0F)); - if(ide_queue->flags & B_WRITE){ - outb(0x1F7, IDE_CMD_WRITE); - outsl(0x1F0, ide_queue->data, 512/4); - } else { - outb(0x1F7, IDE_CMD_READ); - } - } + // Read data if needed. + if((b->flags & B_WRITE) == 0 && ide_wait_ready(1) >= 0) + insl(0x1f0, b->data, 512/4); + + // Wake process waiting for this buf. + b->done = 1; + wakeup(b); + + // Start disk on next buf in queue. + if((ide_queue = b->qnext) != 0) + ide_start_request(ide_queue); + + release(&ide_lock); } -//PAGEBREAK: 30 -// Queue up a disk operation and wait for it to finish. -// b must have B_BUSY set. +//PAGEBREAK! +// Queue a disk operation and wait for it to finish. void ide_rw(struct buf *b) { struct buf **pp; - if((b->dev & 0xff) && !disk_1_present) + if(!(b->flags & B_BUSY)) + panic("ide_rw: buf not busy"); + if(b->dev != 0 && !disk_1_present) panic("ide disk 1 not present"); acquire(&ide_lock); + // Append b to ide_queue. b->done = 0; b->qnext = 0; - - // append b to ide_queue - pp = &ide_queue; - while(*pp) - pp = &(*pp)->qnext; + for(pp=&ide_queue; *pp; pp=&(*pp)->qnext) + ; *pp = b; + // Start disk if necessary. if(ide_queue == b) - ide_start_request(); + ide_start_request(b); + // Wait for request to finish. while(!b->done) sleep(b, &ide_lock); - release(&ide_lock); }