diskdevice-model.c
来自「一个用在mips体系结构中的操作系统」· C语言 代码 · 共 1,659 行 · 第 1/4 页
C
1,659 行
#ifndef SOLO if (simosInterface[disk].dmaRoutine) { TICS current_time = CPUVec.CycleCount(0); if (current_time > finish) { /* This can only happen under Embra */ finish = current_time; } simosInterface[disk].dmaRoutine( SECTOR_SIZE, finish, DmaDone, simosInterface[disk].doneArg); } else { DDEventRequest(ENDBUSXFER, finish, disk); }#else DDEventRequest(ENDBUSXFER, finish, disk);#endif}/* @SUBTITLE "EndBusXfer: end one-sector bus xfer, start another" *//* * End a bus transfer at the given eventTime. * * !! EndBusXfer() should only advance ds->currentBusXfer. It should by * !! no means change ds->nextBusXfer. */PRIVATE voidEndBusXfer(int disk, TICS eventTime){ struct diskstatus *ds = &(dstatus[disk]); boolean finished; DEBUG_TRACE(("EndBusXfer \t%d\t@%s: currentBusXfer = %lu\n", disk, time_print(eventTime), ds->currentBusXfer)); ds->currentBusXfer++;#ifndef SOLO /* If we have transfered all of the active cache across the bus, we can now flush it, to allow it to be refilled. This allows us to do disk transfers that are larger than the cache size. */ if (ds->reading && (ds->currentBusXfer == ds->currentDiskXfer)) ds->firstCachedSector = ds->currentDiskXfer;#endif if ((ds->nextBusXfer <= ds->lastSector) && ((ds->reading && ds->nextBusXfer < ds->currentDiskXfer) || (!ds->reading && !CACHE_FULL(disk)))) DDEventRequest(STARTBUSXFER, eventTime, disk); else { finished = (ds->nextBusXfer > ds->lastSector); ds->activeBusXfer = FALSE; ds->wantBus = (finished ? NEVER : eventTime); #ifdef IMMEDIATE_REPORT if (finished) DDEventRequest(SENDDONEMESSAGE, eventTime, disk);#else if (finished) if (ds->reading) DDEventRequest(SENDDONEMESSAGE, eventTime, disk); else /* give the bus to the next event on the bus queue */ PassBus(disk, eventTime);#endif /* IMMEDIATE_REPORT */ } if (ds->needMove) { ds->needMove = FALSE; /* reset the value */ /* move to appropriate location */ DDEventRequest(DISKMOVE, eventTime, disk); }}/* @SUBTITLE "SendDoneMessage: send a 'done' message to host" */PRIVATE voidSendDoneMessage(int disk, TICS eventTime){ TICS grabTime = 0; /* time it took to grab the bus */ DEBUG_TRACE(("SendDoneMessage\t%d\t@%s: nextDiskXfer = %lu\n", disk, time_print(eventTime), dstatus[disk].nextDiskXfer)); if (GrabBus(disk, &grabTime, eventTime)) { DDEventRequest(ENDDONEMESSAGE, (eventTime + grabTime +DONETIME_t), disk); if (grabTime > 0) INDEX_TIME_EVENT(EV_BUSSTATE, dstatus[disk].busId, BUSSTATE_GRAB, eventTime); INDEX_TIME_EVENT(EV_BUSSTATE, dstatus[disk].busId, BUSSTATE_COMMAND, eventTime + grabTime); } else { DEBUG_TRACE(("SendDoneMessage: Waiting for bus\n")); WaitForBus(disk, SENDDONEMESSAGE, eventTime); } }/* @SUBTITLE "EndDoneMessage: 'done' message reaches host; wakeup thread" */PRIVATE voidEndDoneMessage(int disk, TICS eventTime){ struct diskstatus *ds = &(dstatus[disk]); DEBUG_TRACE(("EndDoneMessage \t%d\t@%s: nextDiskXfer = %lu\n", disk, time_print(eventTime), ds->nextDiskXfer)); /* give the bus to the next event on the bus queue */ PassBus(disk, eventTime); DDEventWakeup(disk,ds->wait_thread, eventTime); /* reset the sync flag */ if (ds->wantSync) ds->wantSync = FALSE;}/* == Utility Functions ================================================= *//* @SUBTITLE "MoveTime_t: return the time when the move is completed" *//* Calculate and return the time taken to move from one disk * sector to another. * * Given the destination sector of the disk and the starting time, * calculate the time when the disk head motion is finished. */TICSMoveTime_t(int disk, ulong lsector, TICS eventTime){ TICS abstime; /* amount of time needed */ ulong dcylinders, dtracks; ulong oldtrack = dstatus[disk].track; ulong sector = Logical2Physical(lsector); ulong track = SECTOR2TRACK(sector); /* calculate the differences in cylinders */ dcylinders = UlongAbsDiff(TRACK2CYLINDER(oldtrack), TRACK2CYLINDER(track)); dtracks = UlongAbsDiff(oldtrack, track); abstime = SeekTime_t(dcylinders, dtracks, eventTime); /* ----------- seek time is calculated, next rotational delay ---------- */ /* include the rotation delay */ abstime = RotDelay_t(disk, sector, abstime); dstatus[disk].track = (int)track; /* remember the new position */ return(abstime);}/* @SUBTITLE "MoveNextTime_t: time needed to move to next logical sector" *//* * Enters with: Disk number, Logical sector number to move the disk * head to and Time the move begins. * Returns: Time the move completes. */PRIVATE TICSMoveNextTime_t(int disk, ulong lsector, TICS eventTime){ struct diskstatus *ds = &(dstatus[disk]); ulong trackswitch, headswitch; ulong oldtrack = SECTOR2TRACK(Logical2Physical(lsector - 1)); ulong newtrack = SECTOR2TRACK(Logical2Physical(lsector)); trackswitch = UlongAbsDiff(TRACK2CYLINDER(oldtrack), TRACK2CYLINDER(newtrack)); headswitch = UlongAbsDiff(oldtrack, newtrack); /* more than one cylinder, eg when crossing a sparing region */ if (trackswitch > 1) { /* crossing a sparing region */ return(MoveTime_t(disk, lsector, eventTime)); } else { ds->track = (int)newtrack; if (trackswitch == 1) /* takes precedence over headswitch */ return(eventTime + TRACK_SWITCH_t); /* only 1 headswitch within a cylinder counts */ else if (headswitch >= 1) return(eventTime + HEAD_SWITCH_t); else return(eventTime); /* no switch occurred */ }}/* @SUBTITLE "RotDelay_t: time to rotate to the desired sector" *//* * Enters with: Number of the disk of significance and the seektime. * Parameter requested is the physical sector number. * Returns: The time the sector requested is reached. */PRIVATE TICSRotDelay_t(int disk, ulong sector, TICS endSeekTime){ double initRotPos = 0; /* initial position is 0 at time 0 */ double dtime; double endSeekRotPos; /* rotational position after the seek */ double destPosition, dPosition; ulong tracksector; endSeekRotPos = initRotPos + (double)(endSeekTime - 0) / ROT_TIME_t; /* find the position in fractions */ endSeekRotPos = endSeekRotPos - (unsigned long) endSeekRotPos; tracksector = sector % NSECTORS; destPosition = ((double) (tracksector + SECTOR2CYLINDER(sector) * CYLINDERSKEW + (SECTOR2TRACK(sector) - SECTOR2CYLINDER(sector)) * TRACKSKEW) / NSECTORS); dPosition = 1 + destPosition - endSeekRotPos; dPosition = dPosition - (unsigned long) dPosition; dtime = dPosition * ROT_TIME_t; return ((TICS)dtime + endSeekTime);}/* @SUBTITLE "SanityCheck: check parameters for errors" *//* * This function checks whether the parameters given to the function * is valid. If they are not, the program will be aborted and an error * message printed. */PRIVATE voidSanityCheck(int disk, ulong lsector, ulong nsectors){ INVARIANT3((disk >= 0 && disk < NO_OF_DISKS), "SanityCheck %d: invalid disk number\n", disk); INVARIANT3(dstatus[disk].startTime == NEVER, "SanityCheck %d: previous DiskDeviceStart not finished!\n", disk); INVARIANT3((lsector < TOTAL_NSECTORS), "SanityCheck %d: starting sector not in disk\n", disk); INVARIANT3((nsectors > 0), "SanityCheck %d: transfer size too small\n", disk); INVARIANT3(((lsector + nsectors - 1) < TOTAL_NSECTORS), "SanityCheck %d: transfer past end of disk\n", disk); INVARIANT3((dstatus[disk].wantBus == NEVER), "%d: previous request not finished\n", disk); INVARIANT3((!dstatus[disk].activeBusXfer), "%d: bus is still busy\n", disk);}/* @SUBTITLE "SeekTime_t: compute the seek-time component of disk move" *//* * This function returns the time when a seek from one sector to the * other will complete. * The number returned is in TICS. */PRIVATE TICSSeekTime_t(ulong dcylinders, ulong dtracks, TICS eventTime){ double dtime; /* as given in pg 14 (3.4.2) of Modelling Disks HPL-93-68 revision 1 if (dcylinders < 616) dtime = (3.45 + 0.597 * sqrt((double)dcylinders)); else dtime = (10.8 + 0.012 * dcylinders); */ /* as given in pg 17, facts for HP 97560 */ if (dcylinders == 0) { if (dtracks != 0) /* time for head switch instead of seek (convert HEAD_SWITCH_t back from TICS to MSEC) */ dtime = (double) HEAD_SWITCH_t / TICSperMSEC; /* just 1 switch */ else dtime = 0; } else if (dcylinders < 383) dtime = (3.24 + 0.400 * sqrt((double)dcylinders)); else dtime = (8.00 + 0.008 * dcylinders); /* convert dtime from msec to TICS */ return ((TICS) (dtime * TICSperMSEC) + eventTime);}/* @SUBTITLE "Logical2Physical: convert logical sector number to physical" *//* Convert a logical sector number to a physical sector number. */PRIVATE ulongLogical2Physical(ulong lsector){ ulong region, psector; for (region = 0; region < NUM_REGIONS; region++) if (lsector <= Regions[region].logicalend) break; /* find the region in which the lsector is situated */ /* calculate the corresponding physical sector number */ psector = Regions[region].physicalstart + (lsector - Regions[region].logicalstart); return (psector);}/* @SUBTITLE "GrabBus: try to grab the bus for ourselves" *//* Try to grab control of the bus. */PRIVATE boolean /* TRUE iff we can use the bus now */GrabBus(int disk, TICS *grabTime, TICS eventTime){ struct diskstatus *ds = &(dstatus[disk]); int *busOwner = ds->busOwner; if (*busOwner == BUS_FREE) { /* bus is available */ *busOwner = disk; /* grab it */ *grabTime = BUSGRABTIME_t; INDEX_TIME_EVENT(EV_BUSCONTEND, ds->busId, 1, eventTime); return(TRUE); } else if (*busOwner == disk) { /* we already have the bus */ *grabTime = 0; return(TRUE); /* ok */ } else { return (FALSE); /* bus not available */ }}/* @SUBTITLE "WaitForBus: wait for our bus to be free" *//* * Wait for the given bus, which is busy. */PRIVATE voidWaitForBus(int disk, REQUESTCODE event, TICS eventTime){ struct diskstatus *ds = &(dstatus[disk]); NCQUEUE *busq = ds->busq; busItem *itemptr = (busItem *) malloc(sizeof(busItem)); INVARIANT2((itemptr != NULL), "WaitForBus: malloc failed\n"); itemptr->disk = disk; /* record who we are and what we want */ itemptr->event = event; Enqueue_noncyc(busq, itemptr); /* put us into the queue waiting for bus */ INDEX_TIME_EVENT(EV_BUSCONTEND, ds->busId, InQueue_noncyc(busq)+1, eventTime);}/* @SUBTITLE "PassBus: pass our bus to a waiter, if any" *//* * Pass the given bus to another disk waiting to use that bus. * 'disk' should be the disk currently holding the bus. */PRIVATE voidPassBus(int disk, TICS eventTime){ struct diskstatus *ds = &(dstatus[disk]); TICS requestTime; /* is there anyone waiting for this bus? */ if (!EmptyQueue_noncyc(ds->busq)) { busItem *itemptr = 0; /* pull off the first disk waiting for this bus */ Dequeue_noncyc(ds->busq, (void **)&itemptr); DEBUG_TRACE(("\tPass bus from %d to %d @%s\n", disk, itemptr->disk, time_print(eventTime))); INVARIANT4(dstatus[itemptr->disk].busOwner == ds->busOwner, "PassBus: disks %lld and %lld don't share a bus!\n", (int64)itemptr->disk, (int64)(ds - dstatus)); INVARIANT3(*(ds->busOwner) == disk, "PassBus: disk %d doesn't own its bus!\n", disk); /* special-case when CONSIDERBUSXFER put STARTBUSXFER on queue */ if (itemptr->event == STARTBUSXFER) { INDEX_TIME_EVENT(EV_BUSSTATE, ds->busId, BUSSTATE_GRAB, eventTime); /* it actually starts a little later */ requestTime = eventTime + BUSGRABTIME_t; } else requestTime = eventTime; /* Give the bus to them right now */ *(ds->busOwner) = itemptr->disk; /* and schedule the event they wanted */ DDEventRequest(itemptr->event, requestTime, itemptr->disk); INDEX_TIME_EVENT(EV_BUSCONTEND, ds->busId, InQueue_noncyc(ds->busq)+1, eventTime); free(itemptr); } else { *(ds->busOwner) = BUS_FREE; INDEX_TIME_EVENT(EV_BUSSTATE, ds->busId, BUSSTATE_IDLE, eventTime); INDEX_TIME_EVENT(EV_BUSCONTEND, ds->busId, 0, eventTime); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?