| // Simple PIO-based (non-DMA) IDE driver code. | |
| // idequeue points to the buf now being read/written to the disk. | |
| // idequeue->qnext points to the next buf to be processed. | |
| // You must hold idelock while manipulating queue. | |
| static struct spinlock idelock; | |
| static struct buf *idequeue; | |
| static int havedisk1; | |
| static void idestart(struct buf*); | |
| // Wait for IDE disk to become ready. | |
| static int | |
| idewait(int checkerr) | |
| { | |
| int r; | |
| while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) | |
| ; | |
| if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0) | |
| return -1; | |
| return 0; | |
| } | |
| void | |
| ideinit(void) | |
| { | |
| int i; | |
| initlock(&idelock, "ide"); | |
| ioapicenable(IRQ_IDE, ncpu - 1); | |
| idewait(0); | |
| // Check if disk 1 is present | |
| outb(0x1f6, 0xe0 | (1<<4)); | |
| for(i=0; i<1000; i++){ | |
| if(inb(0x1f7) != 0){ | |
| havedisk1 = 1; | |
| break; | |
| } | |
| } | |
| // Switch back to disk 0. | |
| outb(0x1f6, 0xe0 | (0<<4)); | |
| } | |
| // Start the request for b. Caller must hold idelock. | |
| static void | |
| idestart(struct buf *b) | |
| { | |
| if(b == 0) | |
| panic("idestart"); | |
| if(b->blockno >= FSSIZE) | |
| panic("incorrect blockno"); | |
| int sector_per_block = BSIZE/SECTOR_SIZE; | |
| int sector = b->blockno * sector_per_block; | |
| int read_cmd = (sector_per_block == 1) ? IDE_CMD_READ : IDE_CMD_RDMUL; | |
| int write_cmd = (sector_per_block == 1) ? IDE_CMD_WRITE : IDE_CMD_WRMUL; | |
| if (sector_per_block > 7) panic("idestart"); | |
| idewait(0); | |
| outb(0x3f6, 0); // generate interrupt | |
| outb(0x1f2, sector_per_block); // number of sectors | |
| outb(0x1f3, sector & 0xff); | |
| outb(0x1f4, (sector >> 8) & 0xff); | |
| outb(0x1f5, (sector >> 16) & 0xff); | |
| outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((sector>>24)&0x0f)); | |
| if(b->flags & B_DIRTY){ | |
| outb(0x1f7, write_cmd); | |
| outsl(0x1f0, b->data, BSIZE/4); | |
| } else { | |
| outb(0x1f7, read_cmd); | |
| } | |
| } | |
| // Interrupt handler. | |
| void | |
| ideintr(void) | |
| { | |
| struct buf *b; | |
| // First queued buffer is the active request. | |
| acquire(&idelock); | |
| if((b = idequeue) == 0){ | |
| release(&idelock); | |
| return; | |
| } | |
| idequeue = b->qnext; | |
| // Read data if needed. | |
| if(!(b->flags & B_DIRTY) && idewait(1) >= 0) | |
| insl(0x1f0, b->data, BSIZE/4); | |
| // Wake process waiting for this buf. | |
| b->flags |= B_VALID; | |
| b->flags &= ~B_DIRTY; | |
| wakeup(b); | |
| // Start disk on next buf in queue. | |
| if(idequeue != 0) | |
| idestart(idequeue); | |
| release(&idelock); | |
| } | |
| //PAGEBREAK! | |
| // Sync buf with disk. | |
| // If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID. | |
| // Else if B_VALID is not set, read buf from disk, set B_VALID. | |
| void | |
| iderw(struct buf *b) | |
| { | |
| struct buf **pp; | |
| if(!holdingsleep(&b->lock)) | |
| panic("iderw: buf not locked"); | |
| if((b->flags & (B_VALID|B_DIRTY)) == B_VALID) | |
| panic("iderw: nothing to do"); | |
| if(b->dev != 0 && !havedisk1) | |
| panic("iderw: ide disk 1 not present"); | |
| acquire(&idelock); //DOC:acquire-lock | |
| // Append b to idequeue. | |
| b->qnext = 0; | |
| for(pp=&idequeue; *pp; pp=&(*pp)->qnext) //DOC:insert-queue | |
| ; | |
| *pp = b; | |
| // Start disk if necessary. | |
| if(idequeue == b) | |
| idestart(b); | |
| // Wait for request to finish. | |
| while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){ | |
| sleep(b, &idelock); | |
| } | |
| release(&idelock); | |
| } | |
Xet Storage Details
- Size:
- 3.61 kB
- Xet hash:
- 0e43b7285e4b08a5d696b453305d82eee4293a891ca5257bb9732cbaf7218d7c
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.