⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide_drive.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 2 页
字号:
}uint32_tide_drive::DoProbe(uint8_t cmd){  if (present && (media != IDE::med_disk) && (cmd == WIN_IDENTIFY)) {    MsgLog::fatal("Drive obviously not IDE\n");    return 4;  }  MsgLog::printf("probing for %s: present=%d, media=%d, probetype=%s hwif=0x%08x\n\n",		 name, present, media,		 (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI",		 hwif);  /* The following OUGHT to be redundant: */  hwif->SelectDrive(ndx);  Machine::SpinWaitMs(DRIVE_SELECT_DELAY);  if (hwif->Get8(IDE_DRV_HD) != select.all  && !present) {    hwif->Put8(IDE_DRV_HD, 0xa0); /* select drive 0 */    MsgLog::printf("Drive didn't select and not present\n");    return 3;  }      uint8_t status = hwif->Get8(IDE_STATUS);  uint8_t rc;    if (OK_STAT(status,READY_STAT,BUSY_STAT) ||      present || cmd == WIN_PIDENTIFY) {        /* try to identify the drive twice: */    if  ((rc = Identify(cmd)))      rc = Identify(cmd);    /* Make sure interrupt status is clear: */    uint8_t status = hwif->Get8(IDE_STATUS);    if (rc)      MsgLog::printf("%s: no response(status = 0x%02x)\n", name,		     status);  }  else {    MsgLog::printf("Drive didn't select\n");    rc = 3;				/* not present or maybe ATAPI */  }    if (select.b.unit != 0) {	/* unit not 0 */    MsgLog::printf("Reselect drive 0. ");    hwif->Put8(IDE_DRV_HD, 0xa0); /* select drive 0 */    Machine::SpinWaitMs(DRIVE_SELECT_DELAY);    /* Make sure interrupt status is clear: */    uint8_t result=hwif->Get8(IDE_CTL_ALTSTATUS);    MsgLog::printf("Alt status : 0x%02x\n", result);        (void) hwif->Get8(IDE_STATUS);  }  return rc;}voidide_drive::Probe(){#if 0  if (noprobe)			/* skip probing? */    return;#endif  if (DoProbe(WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */    (void) DoProbe(WIN_PIDENTIFY); /* look for ATAPI device */  }  if (!present)    return;			/* drive not found */  needsMount = true;    /* Double check the results of the probe: */    if (id == NULL) {		/* identification failed? */    if (media == IDE::med_disk) {      MsgLog::printf("%s: old drive, CHS=%d/%d/%d\n",		     name, b_chs.cyl, b_chs.hd, b_chs.sec);    }    else if (media == IDE::med_cdrom) {      MsgLog::printf("%s: ATAPI CDROM?\n", name);    }    else {      present = false;	/* nuke it */    }  }}voidide_drive::DoDriveCommand(Request * /* req */){  MsgLog::fatal("Drive commands not implemented\n");}/* * do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. * It also takes care of issuing special DRIVE_CMDs. */#if 0static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)#endifvoidide_drive::DoDiskRequest(Request *req){  /* NOTE: Plug requests are handled in ide_hwif::StartRequest() */    hwif->Put8(IDE_CTL_ALTSTATUS, ctl);  /* We can do the whole transfer until proven otherwise. */  req->nsec = req->req_nsec;    uint8_t sec, hd;  uint16_t cyl;  uint8_t sel = 0;    if (select.b.lba) {#if defined(IDE_DEBUG)    MsgLog::printf("%s: %sing: LBAsect=%d, sectors=%d, buffer=0x%08x\n",	   name, (req->cmd==Request::Read)?"read":"writ",	   req->req_start, req->nsec, (unsigned long) req->req_ioaddr);#endif    sec = req->req_start;    cyl = req->req_start >> 8;    hd = (req->req_start >> 24) & 0x0f;      } else {    uint32_t track = req->req_start / l_chs.sec;    sec = req->req_start % l_chs.sec;        hd  = track % l_chs.hd;    cyl  = track / l_chs.hd;    sec++;#if defined(IDE_DEBUG)    MsgLog::printf("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08x\n",	   name, (req->cmd==Request::Read)?"read":"writ", cyl,	   hd, sec, req->nsec, (unsigned long) req->req_ioaddr);#endif  }  sel = hd | select.all;  /* IDE can always issue a request for more sectors than we need.  We   * go ahead and issue the request for the complete read here.   *    * FIX: Someday we need a strategy here for error recovery.   */    hwif->Put8(IDE_NSECS, req->nsec);  hwif->Put8(IDE_SECTOR, sec);  hwif->Put8(IDE_CYL_LO, cyl);  hwif->Put8(IDE_CYL_HI, cyl >> 8);  hwif->Put8(IDE_DRV_HD, sel);#if defined(IDE_DEBUG)  MsgLog::printf("Start %s: start %d nsec %d at 0x%08x\n",		 ((req->cmd == Request::Read) ? "read" : "write"),		 req->req_start, req->req_nsec, req->req_ioaddr);#endif#if 0  if (IS_PROMISE_DRIVE) {    if (hwif->is_promise2 || rq->cmd == READ) {      do_promise_io (drive, rq);      return;    }  }#endif  if (req->cmd == IoCmd::Read) {#if defined(IDE_DEBUG)    uint8_t status = hwif->Get8(IDE_STATUS);    MsgLog::printf("Status prior to initating: 0x%x\n", status);#endif    /* If we are able to use DMA, do so. */    assert (use_dma == false);    if (use_dma && hwif->dma_handler(ide_hwif::dma_read, this))      return;    hwif->SetHandler(ndx, &ide_hwif::ReadIntr);    hwif->Put8(IDE_CMD, multCount ? WIN_MULTREAD : WIN_READ);#if defined(IDE_DEBUG)    MsgLog::dprintf(false, "Return from DoDiskRequest\n");#endif    return;  }  if (req->cmd == IoCmd::Write) {    /* Use multwrite whenever possible. */    assert (use_dma == false);    if (use_dma && hwif->dma_handler(ide_hwif::dma_write, this))      return;    hwif->Put8(IDE_CMD, multCount ? WIN_MULTWRITE : WIN_WRITE);    if ( WaitStatus(DATA_READY, BAD_W_STAT, WAIT_DRQ) ) {      MsgLog::printf("%s: no DRQ after issuing %s\n", name,	     multCount ? "MULTWRITE" : "WRITE");      return;    }    if (multCount) {      hwif->group->curReq = req;      hwif->SetHandler (ndx, &ide_hwif::MultWriteIntr);      MultWrite(req);    } else {      hwif->SetHandler (ndx, &ide_hwif::WriteIntr);      OutputData((void*) req->req_ioaddr, EROS_SECTOR_SIZE >> 2);    }    return;  }#if 0  MsgLog::printf("%s: bad command: %d\n", drive->name, rq->cmd);  ide_end_request(0, HWGROUP(drive));#endif}voidide_drive::EndDriveCmd(uint8_t /* stat */, uint8_t /* err */){  MsgLog::fatal("Drive end command not implemented\n");}/* * Error reporting, in human readable form (luxurious, but a memory hog). */uint8_tide_drive::DumpStatus (const char *msg, uint8_t stat, Request* req){  uint8_t err = 0;  MsgLog::printf("%s: %s: status=0x%02x", name, msg, stat);#ifdef FANCY_STATUS_DUMPS  if (media == IDE::med_disk) {    MsgLog::printf(" { ");    if (stat & BUSY_STAT)      MsgLog::printf("Busy ");    else {      if (stat & READY_STAT)	MsgLog::printf("DriveReady ");      if (stat & WRERR_STAT)	MsgLog::printf("DeviceFault ");      if (stat & SEEK_STAT)	MsgLog::printf("SeekComplete ");      if (stat & DRQ_STAT)	MsgLog::printf("DataRequest ");      if (stat & ECC_STAT)	MsgLog::printf("CorrectedError ");      if (stat & INDEX_STAT)	MsgLog::printf("Index ");      if (stat & ERR_STAT)	MsgLog::printf("Error ");    }    MsgLog::printf("}");  }#endif	/* FANCY_STATUS_DUMPS */  MsgLog::printf("\n");  if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {    err = hwif->Get8(IDE_ERROR);    MsgLog::printf("%s: %s: error=0x%02x", name, msg, err);#ifdef FANCY_STATUS_DUMPS    if (media == IDE::med_disk) {      MsgLog::printf(" { ");      if (err & BBD_ERR)	MsgLog::printf("BadSector ");      if (err & ECC_ERR)	MsgLog::printf("UncorrectableError ");      if (err & ID_ERR)		MsgLog::printf("SectorIdNotFound ");      if (err & ABRT_ERR)	MsgLog::printf("DriveStatusError ");      if (err & TRK0_ERR)	MsgLog::printf("TrackZeroNotFound ");      if (err & MARK_ERR)	MsgLog::printf("AddrMarkNotFound ");      MsgLog::printf("}");      if (err & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {	uint8_t cur = hwif->Get8(IDE_DRV_HD);	if (cur & 0x40) {	/* using LBA? */	  MsgLog::printf(", LBAsect=%ld", (unsigned long)		 ((cur&0xf)<<24)		 |(hwif->Get8(IDE_CYL_HI)<<16)		 |(hwif->Get8(IDE_CYL_LO)<<8)		 | hwif->Get8(IDE_SECTOR));	} else {	  MsgLog::printf(", CHS=%d/%d/%d",		 (hwif->Get8(IDE_CYL_HI)<<8) + hwif->Get8(IDE_CYL_LO),		 cur & 0xf,	/* ?? WHY the limit ?? */		 hwif->Get8(IDE_SECTOR));	}	if (req)	  MsgLog::printf(", sector=%ld", req->req_start);      }    }#endif	/* FANCY_STATUS_DUMPS */    MsgLog::printf("\n");  }  return err;}/* * Error() takes action based on the error returned by the controller. */voidide_drive::Error(const char *msg, uint8_t stat){  Request *req = rq.GetNextRequest();  uint8_t err;  err = DumpStatus(msg, stat, req);  if (req  == NULL)    return;  /* retry only "normal" I/O: */  if (req->cmd == IoCmd::NUM_IOCMD) {    req->nError = 1;    EndDriveCmd(stat, err);    return;  }  if (stat & BUSY_STAT) {		/* other bits are useless when BUSY */    req->nError |= ERROR_RESET;  }  else {    if (media == IDE::med_disk && (stat & ERR_STAT)) {      /* err has different meaning on cdrom and tape */      if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */	req->nError = ERROR_MAX;      else if (err & TRK0_ERR)	/* help it find track zero */	req->nError |= ERROR_RECAL;    }    if ((stat & DRQ_STAT) && req->cmd != IoCmd::Write)      FlushResidue();  }  uint8_t status = hwif->Get8(IDE_STATUS);  if (status & (BUSY_STAT|DRQ_STAT))    req->nError |= ERROR_RESET;	/* Mmmm.. timing problem */  if (req->nError >= ERROR_MAX) {#ifdef CONFIG_BLK_DEV_IDETAPE    if (drive->media == ide_tape) {      req->nError = 0;      idetape_end_request(0, HWGROUP(drive));    }    else#endif /* CONFIG_BLK_DEV_IDETAPE */      /* Terminate the request: */      req->Terminate();  }  else {    if ((req->nError & ERROR_RESET) == ERROR_RESET) {      ++req->nError;      hwif->DoReset(ndx);      return;    }    else if ((req->nError & ERROR_RECAL) == ERROR_RECAL)      flags.b.recal = 1;    ++req->nError;  }  MsgLog::dprintf(true, "A drive error occurred on drive %s\n",		  name);}/* FlushResidue() is invoked in response to a drive unexpectedly * having its DRQ_STAT bit set.  As an alternative to resetting the * drive, this routine tries to clear the condition by read a sector's * worth of data from the drive.  Of course, this may not help if the * drive is *waiting* for data from *us*. */voidide_drive::FlushResidue(){  uint32_t i = (multCount ? multCount : 1) * EROS_SECTOR_SIZE / 2; /* 16-bit xfers */  while (i > 0) {    unsigned long buffer[16];    unsigned int wcount = (i > 16) ? 16 : i;    i -= wcount;    InputData(buffer, wcount);  }}/* * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT * commands to a drive.  It used to do much more, but has been scaled back. */voidide_drive::HandleDriveFlags(){#if 0next:#endif  MsgLog::printf("%s: do_special: 0x%02x\n", name, flags.all);  if (flags.b.setGeom) {    flags.b.setGeom = 0;        if (media == IDE::med_disk) {      hwif->Put8(IDE_SECTOR, l_chs.sec);      hwif->Put8(IDE_CYL_LO, l_chs.cyl);      hwif->Put8(IDE_CYL_HI, l_chs.cyl >> 8);      hwif->Put8(IDE_DRV_HD, (l_chs.hd - 1 | select.all) & 0xBFu);      if (!IS_PROMISE_DRIVE)	hwif->DoCmd(ndx, WIN_SPECIFY, l_chs.sec, &ide_hwif::SetGeometryIntr);    }  }  else if (flags.b.recal) {    flags.b.recal = 0;    if (media == IDE::med_disk && !IS_PROMISE_DRIVE)      hwif->DoCmd(ndx, WIN_RESTORE, l_chs.sec, &ide_hwif::RecalibrateIntr);  }#if 0  else if (flags.b.set_pio) {    ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;    flags.b.set_pio = 0;    if (tuneproc != NULL)      tuneproc(drive, drive->pio_req);    goto next;  }#endif  else if (flags.b.setMultMode) {    flags.b.setMultMode = 0;    if (media == IDE::med_disk) {      if (id && multReq > id->max_multsect)	multReq = id->max_multsect;      MsgLog::printf("ship a WIN_SETMULT command multReq %d max %d\n",		     multReq, id->max_multsect);      if (!IS_PROMISE_DRIVE)	hwif->DoCmd(ndx, WIN_SETMULT, multReq, &ide_hwif::SetMultmodeIntr);    }    else      multReq = 0;  }  else if (flags.all) {    uint8_t old_flags = flags.all;    flags.all = 0;    MsgLog::printf("%s: bad special flag: 0x%02x\n", name, old_flags);  }}/* Busy wait for the drive to return the expected status, but not for * longer than timelimit.  Return true if there was an error. */boolide_drive::WaitStatus(uint8_t good, uint8_t bad, uint32_t timelimit){  timelimit = Machine::MillisecondsToTicks(timelimit);  timelimit += SysTimer::Now();    do {    /* The IDE spec allows the drive 400ns to get it's act together,     * This is incredibly stupid, as it guarantees at least a 1ms     * delay whenever the status needs to be checked.  Common case is     * that we will do the loop only once.     *      * Note that this code needs to be redesigned, because the busy     * wait loop has very bad implications for real-time.     */    #ifdef VERBOSE_BUG    uint32_t f = GetFlags();    MsgLog::printf("Before SpinWait: flags 0x%08x timer %s enabled.\n",		   f,		   IRQ::IsEnabled(0) ? "is" : "is not");#endif    Machine::SpinWaitUs(1);    uint8_t status = hwif->Get8(IDE_STATUS);      if ( OK_STAT(status,good, bad) )      return false;    /* If the drive no longer purports to be busy, life is bad: */    if ( (status & BUSY_STAT) == 0 ) {      Error("status error", status);      return true;    }  } while( timelimit < SysTimer::Now() );  uint8_t status = hwif->Get8(IDE_STATUS);  Error("status timeout", status);  return true;}/* This routine will not be called unless there is really a request to * process. */voidide_drive::DoRequest(Request * req){#if defined(IDE_DEBUG)  MsgLog::printf("selecting drive %d\n", ndx);#endif    hwif->SelectDrive(ndx);  /* This causes infinite loop for some reason:   *  Machine::SpinWaitMs(DRIVE_SELECT_DELAY);   */  if ( WaitStatus(READY_STAT, BUSY_STAT|DRQ_STAT, WAIT_READY) ) {    MsgLog::fatal("Drive not ready\n");    return;  }    if (flags.all) {    HandleDriveFlags();#if defined(IDE_DEBUG)    MsgLog::dprintf(false, "Handling driver flags\n");#endif    return;  }  if ( req->cmd >= IoCmd::NUM_IOCMD )    DoDriveCommand(req);  else {    switch (media) {    case IDE::med_disk:      DoDiskRequest(req);      break;    default:      MsgLog::fatal("Unimplemented media!\n");    }  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -