📄 ide_ide.cxx
字号:
req->req_start += nsec; req->req_ioaddr += (EROS_SECTOR_SIZE * nsec); req->req_nsec -= nsec; req->nError = 0; req->nsec -= nsec;#ifdef IDE_DEBUG MsgLog::printf("Rd Residual at 0x%08x: %d sectors at %d nsec %d\n", req->req_ioaddr, req->req_nsec, req->req_start, req->nsec); #endif return (req->req_nsec) ? false : true;}boolide_hwif::WriteIntr(){ uint8_t status = Get8(IDE_STATUS); if (!OK_STAT(status,DRIVE_READY,BAD_W_STAT)) { drive[cur_drive].Error("write intr", status); return true; } Request *req = group->curReq; uint32_t nsec = req->nsec; req->req_start += nsec; req->req_ioaddr += (EROS_SECTOR_SIZE * nsec); req->req_nsec -= nsec; req->nError = 0; req->nsec -= nsec;#ifdef IDE_DEBUG MsgLog::printf("Wr Residual at 0x%08x: %d sectors at %d nsec %d\n", req->req_ioaddr, req->req_nsec, req->req_start, req->nsec); #endif /* If the drive is ready and there is more to do, ship off the next * sector, else we will have to reschedule it later. */ if (req->req_nsec && (status & DRQ_STAT)) { assert( status & DRQ_STAT ); drive[cur_drive].OutputData((void*) req->req_ioaddr, EROS_SECTOR_SIZE >> 2); return false; /* let the interrupt handler pointer stand */ } return true;}/* This interrupt hits when the disk is ready for the next multisector * block write. If we get the block size we want (4096), we won't * ever be writing more than 4096 bytes, but conceivably a * user-initiated raw disk I/O might, so we need to be prepared for * that case. */boolide_hwif::MultWriteIntr(){ uint8_t status = Get8(IDE_STATUS); if (!OK_STAT(status,DRIVE_READY,BAD_W_STAT)) { drive[cur_drive].Error("multwrite intr", status); return true; } Request *req = group->curReq; uint32_t nsec = req->nsec; req->req_start += nsec; req->req_ioaddr += (EROS_SECTOR_SIZE * nsec); req->req_nsec -= nsec; req->nError = 0; req->nsec -= nsec;#ifdef IDE_DEBUG MsgLog::printf("MWr Residual at 0x%08x: %d sectors at %d nsec %d\n", req->req_ioaddr, req->req_nsec, req->req_start, req->nsec); #endif /* If the drive is ready and there is more to do, ship off the next * block, else we will have to reschedule it later. */ if (req->req_nsec && (status & DRQ_STAT)) { assert( status & DRQ_STAT ); drive[cur_drive].MultWrite(req); return false; /* let the interrupt handler pointer stand */ } return true;}voidide_hwif::OnIntr(IntAction* ia){ ide_hwif *pHwif = (ide_hwif*) ia->drvr_ptr; if (pHwif->int_handler == 0) { uint8_t status = pHwif->Get8(IDE_STATUS); pHwif->drive[0].DumpStatus("orphaned interrupt", status, 0);#if 0 pHwif->drive[0].flags.b.recal = 1; pHwif->drive[1].flags.b.recal = 1; halt();#endif } /* Call pointer to member that happens to be member of pHwif */ if ( (pHwif->*(pHwif->int_handler))() ) {#ifdef IDE_DEBUG MsgLog::printf("OnIntr() Set int handler to 0\n");#endif pHwif->int_handler = 0; pHwif->next = readyChain; readyChain = pHwif; ActivateTask(); }}voidide_hwif::StartIO(){ group->StartIO();}/* FIX: This needs a much more sophisticated selection policy. Right * now it does round-robin issuance among all of the HWIF's in a group * to prevent starvation. On drives with write-back buffers this isn't * a big problem, but most drives still use write-through logic, and * on these drives the current policy results in bad rotational * delays. At 7200 RPM, the on-paper mean rotational delay is * 60/(7200*2) or about 4.2 ms. Since we write blocks sequentially, * it is damn likely that we will get close to worst case rotational * delay of 8ms (I need to measure this). * * A better policy would be to have the StartIO() routine examine the * next request on the same drive and see if that request falls on the * same PHYSICAL cylinder **and track** as the previous request. If * so, it should endeavour to issue the request eagerly. * * There is no point doing more than a track on a modern drive -- head * to head delays closely approximate track to track delays, and we * might as well switch to the next interface. * * Even better would be to do request merging, coalescing adjacent I/O * operations into a single operation using chained DMA. This would * make maximal use of the disk cache and the rotational advantage. */voidide_group::StartIO(){ assert(this); do { if (curReq == 0) { for (uint32_t i = 0; i < HWIFS_PER_GROUP; i++) { uint32_t which_hwif = (cur_hwif + i + 1) % HWIFS_PER_GROUP; if (hwif[which_hwif] == 0) continue; curReq = hwif[which_hwif]->GetNextRequest(); if (curReq) { cur_hwif = which_hwif; break; } } } if (curReq == 0) return; #if defined(IDE_DEBUG) MsgLog::dprintf(false, "Start cur_hwif = 0x%08x, req=0x%08x dio=0x%08x\n", hwif[cur_hwif], curReq, curReq->dio);#endif } while ( hwif[cur_hwif]->StartRequest(curReq) );}Request*ide_hwif::GetNextRequest(){ /* The point of this madness is to cycle through the configured * drives exactly once, while still doing round-robin initiation. */ for (uint32_t i = 0; i < MAX_DRIVE; i++) { uint32_t unit = (cur_drive + i + 1) % MAX_DRIVE; if ( drive[unit].present && !drive[unit].rq.IsEmpty() ) { cur_drive = unit; return drive[unit].rq.GetNextRequest(); } } return 0;}/* Return true when request is completed. */boolide_hwif::StartRequest(Request* req){ /* We don't do split-seek on IDE drives, so just go ahead and commit * the request. */ assert(this); assert(req); if (inDuplexWait) return false; if ( int_handler ) {#if defined(IDE_DEBUG) MsgLog::dprintf(true, "HWIF already active (handler=0x%08x)\n", &int_handler);#endif return false; } if ( ! req->Commit(this, &drive[req->unit]) ) { /* stalled by another controller */#if defined(IDE_DEBUG) MsgLog::dprintf(true, "Stalled by another controller\n");#endif return false; } if ( req->IsCompleted() ) { RequestQueue& rq = drive[req->unit].rq; assert (req == group->curReq); req->Finish(); assert ( rq.ContainsRequest(req) ); rq.RemoveRequest(req); group->curReq = 0;#if defined(IDE_DEBUG) if (req->cmd == IoCmd::Plug) MsgLog::printf("IDE%d: plug passes\n", req->unit); MsgLog::dprintf(false, "Finish current request. More? %c\n", rq.IsEmpty() ? 'n' : 'y');#endif return true; } #ifdef IDE_DEBUG MsgLog::dprintf(false, "Calling DoRequest w/ req=0x%08x...\n", req);#endif drive[req->unit].DoRequest(req); return false;}voidide_hwif::Probe(){ if (noprobe) { MsgLog::printf("Skipping probe on IDE interface %d\n", ndx); return; } if (ioBase == BIOS_HD_BASE) { /* Check the CMOS configuration settings. If a CMOS configuration * is found, then this is either BIOS drive 0x80 or 0x81, and the * interface is register compatible with the prehistoric register * interface. This implies that the drive in question is NOT, for * example, a OPTION_SCSI drive. * * FIX: On newer BIOS, CMOS appears to store info for four drives. * How to get it if present? */ uint8_t cmos_hds = CMOS::cmosByte(0x12); if (cmos_hds) present = true; /* HW interface present */ uint8_t cmos_hd0 = (cmos_hds >> 4) & 0xfu; uint8_t cmos_hd1 = cmos_hds & 0xfu; /* If the drives are listed in the CMOS, extract their geometry * from the BIOS tables. */ if (cmos_hd0) { /* * form a longword representing all this gunk: * 6 bit zero * 10 bit cylinder * 8 bit head * 8 bit sector */ drive[0].b_chs.cyl = SysConfig.driveGeom[0].cyls; drive[0].b_chs.hd = SysConfig.driveGeom[0].heads; drive[0].b_chs.sec = SysConfig.driveGeom[0].secs; drive[0].l_chs = drive[0].b_chs; MsgLog::printf("ide0: c/h/s=%d/%d/%d\n", drive[0].b_chs.cyl, drive[0].b_chs.hd, drive[0].b_chs.sec); drive[0].present = true; } if (cmos_hd1) { drive[1].b_chs.cyl = SysConfig.driveGeom[1].cyls; drive[1].b_chs.hd = SysConfig.driveGeom[1].heads; drive[1].b_chs.sec = SysConfig.driveGeom[1].secs; drive[1].l_chs = drive[1].b_chs; MsgLog::printf("ide1: c/h/s=%d/%d/%d\n", drive[1].b_chs.cyl, drive[1].b_chs.hd, drive[1].b_chs.sec); drive[1].present = true; } } if (IoRegion::IsAvailable(ioBase, 8) == false || IoRegion::IsAvailable(ioBase + IDE_CTL_ALTSTATUS, 2) == false) { for (uint32_t unit = 0; unit < MAX_DRIVE; unit++) { if (drive[unit].present) MsgLog::fatal("IDE: hwif %d drive %d present but ports in use\n", ndx, unit); } MsgLog::printf("IDE hwif %d ports in use - skipping probe\n", ndx); present = false; return; } for (uint32_t unit = 0; unit < MAX_DRIVE; unit++) { drive[unit].Probe(); if (drive[unit].present && !present) { present = true; IoRegion::Allocate(ioBase, 8, "ide"); IoRegion::Allocate(ioBase + IDE_CTL_ALTSTATUS, 2, "ide"); } } if (!present) return; if (!irq) irq = ide_irq[ndx]; MsgLog::printf("Registering IDE driver (this=0x%08x)...\n", this); Register(); if (!irq) { MsgLog::printf("ide%d disabled: no IRQ\n", ndx); /* FIX: should unregister */ return; } { uint8_t result=Get8(IDE_CTL_ALTSTATUS); MsgLog::printf("Before int register. Alt status : 0x%02x\n", result); } IntAction *ia = new IntAction(irq, ide_name[ndx], ide_hwif::OnIntr); ia->drvr_ptr = this; IRQ::WireExclusive(ia); MsgLog::printf("Check pending interrupt: IRQ %d\n", irq); IRQ::Enable(irq);#if 0 MsgLog::printf("Intentional halt...\n"); halt();#endif}static boolProbe(struct AutoConf* /* ac */){ IDE::InitChipsets(); for (int ctrlr = 0; ctrlr < MAX_HWIF; ctrlr++) hwif_tbl[ctrlr].Probe();#if 0 /* assume first drive is a 1.44 */ TheHardDiskCtrlr.unit[0]->mediaInfo = &MediaParams[4]; for(int i= 1; i <=HardDiskCtrlr::NUNITS;i++) TheHardDiskCtrlr.unit[i] = 0; /* assume the other drives do */ /* not exist */ TheHardDiskCtrlr.Wakeup();#endif return true;}static boolAttach(struct AutoConf* /* ac */){ return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -