📄 hd.c
字号:
int node, u, c; if (restoreFromChkpt) { /* For now, only support restoring the disk devices on the rmtaccess server which is servicing the checkpoint restore -- supporting 'fallback' is slightly tricky given the current code structure, so I'm not implementing it for now */ if (Simcpt_IsRemote()) { rmtdiskfd = Simrmt_diskinit(NULL); if (rmtdiskfd < 0) CPUError("Can't contact remote disk machine\n"); if (Simcpt_Restore("diskdev") != 0) CPUError("Can't contact remote disk machine\n"); } else { if (DevFileDir[0] == '$') { rmtdiskfd = Simrmt_diskinit(DevFileDir); if (rmtdiskfd < 0) CPUError("Can't contact remote disk machine\n"); } if (Simcpt_Restore("diskdev") != 0) { CPUError("Can't restore disk devices\n"); } } for (node = 0; node < nnode; node++) { if (!dks[node]) continue; for (c = 0; c < nctrl[node]; c++) { if (!dks[node][c]) continue; for (u = 0; u < nunit[node][c]; u++) { if (!dks[node][c][u]) continue; DKS(node,c,u).cmd[0] = CMD_NONE; /* no SCSI command pending */ } } } } else { if (DevFileDir[0] == '$') { rmtdiskfd = Simrmt_diskinit(DevFileDir); if (rmtdiskfd < 0) { CPUError("Can't contact remote disk machine\n"); } } }}static intSimhdOpenCOWDisk(int node, int ctrl, int unit, SimhdSaveInfo *hd){ off_t size; if (rmtdiskfd < 0) { hd->dfd = open(hd->filename, O_RDONLY , 0); if (hd->dfd < 0) { if (errno != ENOENT) { CPUWarning("Simhd: could not open %s COW, errno=%d\n", hd->filename, errno); } return -1; } else { struct stat filestats; size = DetermineDeviceSize(hd->dfd); if (size < 1024*1024) { CPUError("SimHD: DISK is smaller than 1MB (%d bytes) !!!\n", size); } fstat(hd->dfd, &filestats); /* If we're restoring from a checkpoint, check fize size and creation time against checkpointed values */ if ((hd->fileSize > 0) && (hd->fileSize != size)) { Sim_Warning("Simhd: Size of disk %s checkpoint is based on " "has changed!\n", DKS_filename(node,ctrl,unit)); } hd->fileSize = size; if ((hd->modifyTime > 0) && (hd->modifyTime != filestats.st_mtime)) { Sim_Warning("Simhd: DISK file checkpoint is based on " "has been modified!\nThis might not work...\n"); } else { hd->modifyTime = filestats.st_mtime; } Sim_Warning("%s opened using Copy On Write.\n", DKS_diskname(node,ctrl,unit)); } } else { DiskFileInfo df; int retval; /* If we have a filename for the disk (checkpoint restore), pass it to the remote access server; if not, hd->filename should be null. */ bzero((char *) &df, sizeof(df)); ASSERT( strlen(hd->filename)+1 < sizeof(df.filename)); strcpy(df.filename,hd->filename); retval = Simrmt_diskcmd(rmtdiskfd, NETDISK_ATTACH, node, ctrl, unit, 0, strlen(df.filename)+1, (byte *)&df); if (retval < 0) { CPUWarning("Open of %s failed on rmtaccess server\n", DKS_diskname(node,ctrl,unit)); return retval; } strcpy(hd->filename,df.filename); hd->fileSize = size = df.fileSize; hd->modifyTime = df.modifyTime; Sim_Warning("%s remotely open using Copy On Write.\n", DKS_diskname(node,ctrl,unit)); } hd->writeable = (char)0; hd->doCheckSum = hd->checkSum = 0; /* The modify map is not allocated until */ /* we actually change the disk, this is */ /* to optimize checkpointing. */ size = (size + (SIM_DISK_SHADOW_BLKSIZE-1)) & ~(SIM_DISK_SHADOW_BLKSIZE-1); { int pageSize = getpagesize(); hd->modifyMapSize = size/SectorSize/8 + 1; /* 8 extra */ hd->modifyMapSize = (hd->modifyMapSize+pageSize-1) & ~(pageSize-1); } hd->modifyMap = NULL; hd->sfd = 0; hd->shadowOffset = NULL; hd->nextWriteOffset = 0; return 0;}static intSimhdOpenDisk(int node, int ctrl, int unit, SimhdSaveInfo *hd){ int retval = 0; if (rmtdiskfd < 0) { hd->dfd = open(hd->filename, O_RDWR , 0); if (hd->dfd < 0) { retval = SimhdOpenCOWDisk(node, ctrl, unit, hd); if (retval < 0) {#if !defined(IRIX6_4) && !defined(SIM_X86) Sim_Warning("%s not opened! file=%s\n", hd->diskname, hd->filename);#endif } } else { CPUWarning("WARNING: %s opened read-write.\n" "WARNING: remember to umount before checkpointing!!!\n", DKS_diskname(node,ctrl,unit)); DKS(node,ctrl,unit).hdcpt.accessed = 1; hd->writeable = (char)1; } if (hd->dfd <= 0) { retval = -1; } } else { /* Rmtaccess disks must be opened COW */ retval = SimhdOpenCOWDisk(node, ctrl, unit, hd); } return retval;}static voidSimhdDoCmd(int node, int ctrl, int unit){ SimhdSaveInfo *hd = &DKS(node,ctrl,unit).hdcpt.simhdStats; int retval = 0; int cmd; char *op; ASSERT(0 <= ctrl && ctrl < nctrl[node] && 0 <= unit && unit < nunit[node][ctrl] && !DKS(node,ctrl,unit).done); /* check whether this disk is opened for the first time */ if ((rmtdiskfd >= 0) && !DKS(node,ctrl,unit).hdcpt.accessed) { /* Opening a disk for the first time via rmtaccess -- don't provide a pathname, attempt to open COW. */ if (!strncmp(hd->filename,"NOTDEF",strlen("NOTDEF"))) { retval = -1; } else { retval = SimhdOpenCOWDisk(node, ctrl, unit, hd); DKS(node,ctrl,unit).hdcpt.accessed = 1; } } else if ((rmtdiskfd < 0) && (hd->dfd <= 0)) { /* assign this disk a name (if it doesn't have one) */ disk_name(node, ctrl, unit); retval = SimhdOpenDisk(node, ctrl, unit, hd); DKS(node,ctrl,unit).hdcpt.accessed = 1; } if (retval < 0 && DKS(node,ctrl,unit).cmd[0] != CMD_INQUIRY ) { DKS(node,ctrl,unit).bytesTransferred = 0; DKS(node,ctrl,unit).errnoVal = errno; DKS(node,ctrl,unit).done = 1; DTRACE('b', node, ctrl, unit); return; } /* interpret the SCSI command and do required setup. The actual data * transfer doesn't take place here, but in the SimhdIOHandler. */ DoScsiCmd(node, ctrl, unit); cmd = DKS(node,ctrl,unit).cmd[0]; if (cmd != CMD_NONE) { char id[10]; op = scsiOpcode[cmd]; ASSERT(op != NULL); sprintf(id, "%i.%i.%i", node, ctrl, unit); Tcl_SetVar2(TCLInterp, "ScsiRequest", "disk", id, 0); Tcl_SetVar2(TCLInterp, "ScsiRequest", "command", op, 0); AnnExec(AnnFind("scsi", op)); Tcl_UnsetVar(TCLInterp, "ScsiRequest", 0); } DTRACE(DKS(node,ctrl,unit).done ? 'd' : 'e', node, ctrl, unit);}/* * Data handler: does the actual I/O to disk. Is called by the * DMA routines (see comments in dma.h). */static voidSimhdIOHandler(DMARequest* req){ int node = DECODE_NODE(req->arg); int ctrl = DECODE_CTRL(req->arg); int unit = DECODE_UNIT(req->arg); Device* dksp = &DKS(node,ctrl,unit); unsigned long offset; int fd; int remote; ASSERT(req->dmaLen > 0); if (req->isDMAWrite) { /** disk input **/ if (dksp->c.currPtr < dksp->c.dataBuffer+SectorSize) { /* data has already been read into dataBuffer */ dksp->c.currPtr += req->dmaLen; } else { /* must fetch a new sector */ if (dksp->hdcpt.simhdStats.writeable) { /* this is a writable disk */ fd = dksp->hdcpt.simhdStats.dfd; offset = (dksp->c.currSector)*SectorSize; if (lseek(fd, offset, SEEK_SET) == -1) CPUError("Can't seek for %s in RD\n", DKS_diskname(node,ctrl,unit)); if (read(fd, dksp->c.dataBuffer, SectorSize) != SectorSize) CPUWarning("Can't read from %s\n", DKS_diskname(node,ctrl,unit)); } else { remote = SimhdFindSector(node,ctrl,unit, dksp->c.currSector,&fd,&offset,1); if (remote) { int retval = Simrmt_diskcmd(rmtdiskfd, NETDISK_READ, node, ctrl, unit, dksp->c.currSector, SectorSize, dksp->c.dataBuffer); if (retval < 0) CPUError("Simhd: error in remote read\n"); } else { int bytesRead; if (lseek(fd, offset, SEEK_SET) == -1) CPUError("Can't seek for %s in RD\n", DKS_diskname(node,ctrl,unit)); bytesRead = read(fd, dksp->c.dataBuffer, SectorSize); if (bytesRead != SectorSize) { CPUWarning("%s: Only read %d bytes at offset %lld \n", DKS_diskname(node,ctrl,unit), bytesRead,(uint64)offset); bzero(dksp->c.dataBuffer+bytesRead,SectorSize-bytesRead); } } } /* update current read state */ dksp->c.currSector++; dksp->c.currPtr = dksp->c.dataBuffer + req->dmaLen; } req->data = dksp->c.currPtr - req->dmaLen; } else { /** disk output **/ ASSERT(req->data == dksp->c.currPtr); dksp->c.currPtr += req->dmaLen; if (dksp->c.currPtr < dksp->c.dataBuffer+SectorSize) { /* buffer up data until one sector filled */ ASSERT(req->remainingLen > 0); /* make sure whole sectors written */ } else { /* buffer filled up, write to disk */ ASSERT(dksp->c.currPtr == dksp->c.dataBuffer+SectorSize); if (dksp->hdcpt.simhdStats.writeable) { int len; /* this is a writable disk */ fd = dksp->hdcpt.simhdStats.dfd; offset = (dksp->c.currSector)*SectorSize; if (lseek(fd, offset, SEEK_SET) == -1) CPUError("Can't seek for %s in RD\n", DKS_diskname(node,ctrl,unit)); len = write(fd, dksp->c.dataBuffer, SectorSize); if (len != SectorSize) { CPUError("Can't write to %s. only %d written out of %d. errno=%d offset=%ld\n", DKS_diskname(node,ctrl,unit),len,SectorSize,errno,(uint64)offset); } } else { SimhdFindSector(node,ctrl,unit, dksp->c.currSector, &fd, &offset, 0); if (lseek(fd, offset, SEEK_SET) == -1) CPUError("Can't seek for %s in WR\n", DKS_diskname(node,ctrl,unit)); if (write(fd, dksp->c.dataBuffer, SectorSize) != SectorSize) CPUWarning("Can't write to shadow file for %s\n", DKS_diskname(node,ctrl,unit)); } /* update current write state */ dksp->c.currSector++; dksp->c.currPtr = dksp->c.dataBuffer; } req->data = dksp->c.currPtr; } ASSERT(dksp->c.currPtr <= dksp->c.dataBuffer+SectorSize);}/* * Start disk i/o. Arguments are: * - (ctrl,unit) = disk * - cmd = SCSI command * - pages = array of page pointers for transfer * - offset = offset into first page */void sim_disk_startio(int node, int ctrl, int unit, unsigned char cmd[SIM_DISK_CMD_SIZE], /*SCSI cmd*/ PA pages[SIM_DISK_MAX_DMA_LENGTH], int offset){ int i; char *op; int cpuNum = CPUVec.CurrentCpuNum(); enum {DISK_MODEL_FIXED_DMA, /* Fixed latency read/write */ DISK_MODEL_HP, /* Realistic latency read/write */ DISK_MODEL_SENSE /* sense-->DMA */ } diskModel; performingSimpleIO = 0; ASSERT(0 <= node && node < nnode && 0 <= ctrl && ctrl < nctrl[node] && 0 <= unit && unit <= nunit[node][ctrl] && offset >= 0 && offset < NBPP && DKS(node,ctrl,unit).done == 0); if (!DKS(node,ctrl,unit).isReady) { Sim_Warning("simhd_startio: device not ready\n"); DKS(node,ctrl,unit).errnoVal = -1; DKS(node,ctrl,unit).done = 1; /* raise interrupt to signal operation done */ if (int_f) int_f(node, ctrl, unit, 1); return; } /* XXXXXXXXXXX * Unfortunately, the kernel does not give a list of phsysical * pages to us. If the buffer was originally in kseg0, the actual * physical address (not paged aligned) is given to us). * simscsi.c (line 674) should eventually be fixed. For now, * we align the pages ourselves * * Actually, it would be even better if we had physical * addresses. For now we convert it here. * XXXXXXXXXXX */ for (i=0; i < SIM_DISK_MAX_DMA_LENGTH && pages[i]; i++ ) { #if defined(SIM_ALPHA) || defined(SIM_X86) DKS(node,ctrl,unit).pAddr[i] = ((PA)pages[i] & ~(NBPP-1));#else DKS(node,ctrl,unit).pAddr[i] = K0_TO_PHYS(((VA)pages[i] & ~(NBPP-1)));#endif } if( i >= SIM_DISK_MAX_DMA_LENGTH ) CPUError("DMA size of %i pages too large.", i); DKS(node,ctrl,unit).pAddr[i] = 0; DKS(node,ctrl,unit).offset = offset;#ifdef DEBUG_HD CPUPrint("\nSim_disk: %s %08x %08x %08x %08x offs=%x\n", DKS_diskname(node,ctrl,unit), pages[0], pages[1], pages[2], pages[3], offset);#endif /* * Decode the command and execute it, if it doesn't require a data * transfer. Otherwise (for I/O commands), set up parameters. Actual * I/O will be kicked below. */ for (i = 0; i < SIM_DISK_CMD_SIZE; i++) DKS(node,ctrl,unit).cmd[i] = cmd[i]; SimhdDoCmd(node,ctrl,unit); if (DKS(node,ctrl,unit).done) { /* raise interrupt to signal operation done */ if (int_f) int_f(node,ctrl, unit, 1); return; } /* * Set up DMA request area */ DKS(node,ctrl,unit).dmaReq.isDMAWrite = DKS(node,ctrl,unit).isRead; DKS(node,ctrl,unit).dmaReq.pAddrs = &DKS(node,ctrl,unit).pAddr[0]; DKS(node,ctrl,unit).dmaReq.offset = DKS(node,ctrl,unit).offset; DKS(node,ctrl,unit).dmaReq.amountMoved = 0; DKS(node,ctrl,unit).dmaReq.handler = SimhdIOHandler; DKS(node,ctrl,unit).dmaReq.data = DKS(node,ctrl,unit).c.dataBuffer; DKS(node,ctrl,unit).dmaReq.arg = ENCODE(node,ctrl,unit); /* XXXXXXX Hack: check this execCpu bussiness*/ DKS(node,ctrl,unit).c.execCpu = (HP_DISK_SCALING(0) > 0 ? 0 :cpuNum); DKS(node,ctrl,unit).c.currPtr = DKS(node,ctrl,unit).c.dataBuffer + (DKS(node,ctrl,unit).isRead ? SectorSize : 0); DKS(node,ctrl,unit).c.currSector = DKS(node,ctrl,unit).sectorNum; /* invalidate cache / tc since this command involves I/O */ CPUVec.DMAInval(M_FROM_CPU(node), DKS(node,ctrl,unit).pAddr); /* select a disk model */ if( DKS(node,ctrl,unit).sectorNum < 0 ) { /* CMD_MODE_SENSE command - who cares about timing?? */ diskModel = DISK_MODEL_SENSE; DKS(node,ctrl,unit).c.currPtr = DKS(node,ctrl,unit).c.dataBuffer; } else diskModel = (strcmp(DISK_MODEL(0), "HP") != 0) ? DISK_MODEL_FIXED_DMA : DISK_MODEL_HP; #if defined(MAGIC_CTRL) && defined(MAGIC_UNIT) if (ctrl == MAGIC_DISK && unit == MAGIC_UNIT && MAGIC_DISK_SECTOR && DKS(node,ctrl,unit).sectorNum == MAGIC_DISK_SECTOR && diskModel == DISK_MODEL_HP ) /* Magic sector is turbo-charged */ diskModel = DISK_MODEL_FIXED_DMA;#endif if( DKS(node,ctrl,unit).sectorNum >= 0 ) { op = (DKS(node,ctrl,unit).isRead ? "RD":"WR"); } else op = "SYS";#if defined(SIM_ALPHA) LogEntry("DISK-req",cpuNum, "disk %i.%i %s size %li sector %li off=0x%x dma=[", ctrl, unit, op, DKS(node,ctrl,unit).sizeInSectors, DKS(node,ctrl,unit).sectorNum, DKS(node,ctrl,unit).offset);#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -