📄 hd.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//***************************************************************** * simhd.c * * Simple SCSI disk device emulation. Emulates a number of * independent disks. Correctly models disk latencies and * DMA transfers, but does not model disk controller contention * (in fact, there is no real notion of a disk controller in * this model). * * This model has evolved from a very simple hard disk driver that worked * with the IRIX "sable" disk driver to someone that can act as a simple * SCSI disk simulator as well as a disk driver. * * Data handling now supported. The DMA uses in all cases * an intermediate buffer for the scatter/gather * * Created by: ?? * Revised by: * Dan Teodosiu, 07/96 Cleaned up code, changed buffering scheme. * Dan Teodosiu, 05/97 Multiple controllers / node. * ****************************************************************/#include <stdio.h>#include <stdlib.h> /* For the use of calloc() */#include <string.h>#include <sys/types.h>#ifndef __alpha#ifndef i386#include <sys/unistd.h>#endif#endif#include <sys/mman.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/signal.h>#ifndef __alpha#ifndef i386#include <sys/ioccom.h>#include <sys/filio.h>#endif#endif#include <sys/time.h>#include <sys/errno.h>#include <errno.h>#include <unistd.h>#include <assert.h>/* #include <poll.h> */#include "sim.h"#include "syslimits.h"#include "simtypes.h"#include "hd.h"#include "checkpoint.h"#include "machine_params.h"#include "cpu_interface.h"#include "sim_error.h"#include "dma.h"#include "../disk/simos_interface.h"#include "remote_access.h"#include "rmtaccess.h"#include "simutil.h"#include "arch_specifics.h"/* * SCSI commands. * * Not all of these are supported in this device. Currently, only * the commands used by IRIX are implemented. */#define CMD_TST_UNIT_RDY 0x0#define CMD_REQ_SENSE 0x3#define CMD_FORMAT 0x4#define CMD_ADD_DEFECTS 0x7#define CMD_READ_6 0x8#define CMD_WRITE_6 0xa#define CMD_INQUIRY 0x12#define CMD_MODE_SELECT 0x15#define CMD_MODE_SENSE 0x1a#define CMD_STARTUNIT 0x1b#define CMD_SEND_DIAG 0x1d#define CMD_PREVREM 0x1e#define CMD_READCAPACITY 0x25#define CMD_READ 0x28#define CMD_WRITE 0x2a#define CMD_SEEK 0x2b#define CMD_ERASE 0x2c#define CMD_RDEFECTS 0x37#define CMD_NONE 0xff /* Flag meaning no SCSI command */static char *scsiOpcode[256] = { "testUnitRdy", NULL, NULL, "reqSense", "format", NULL, NULL, "addDefects", "read6", NULL, "write6", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "inquiry", NULL, NULL, "modeSelect", NULL, NULL, NULL, NULL, "modeSense", "startunit", NULL, "sendDiag", "prevrem", NULL, NULL, NULL, NULL, NULL, NULL, "readcapacity", NULL, NULL, "read", NULL, "write", "seek", "erase", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rdefects"};/* Taken from /usr/include/sys/dksc.h *//* The data structure of the mode sense command */struct mode_sense_data { u_char sense_len; u_char mediatype; u_char wprot:1, reserv0:2, dpofua:1, reserv1:4; u_char bd_len; u_char block_descrip[8]; /* Don't need this: union dk_pages dk_pages; */};/* from io/cam/scsi_all.h */typedef struct all_inq_data { u_char dtype : 5, /* Peripheral device type. [0] */ pqual : 3; /* Peripheral qualifier. */ u_char dmodify : 7, /* Device type modifier. [1] */ rmb : 1; /* Removable media. */ u_char ansi : 3, /* ANSI version. [2] */ ecma : 3, /* ECMA version. */ iso : 2; /* ISO version. */ u_char rdf : 4, /* Response data format. [3] */ : 2, /* Reserved. */ trmiop : 1, /* Terminate I/O process */ aenc : 1; /* Async Notification of events */ u_char addlen; /* Additional length. [4] */ u_char : 8; /* Reserved. [5] */ u_char : 8; /* Reserved. [6] */ u_char sftre : 1, /* Soft reset 1 = yes [7] */ cmdque : 1, /* Command queuing */ : 1, /* Reserved bit */ linked : 1, /* Linked command support */ sync : 1, /* Synchronous data transfers */ wbus16 : 1, /* support of 16 bit transfers */ wbus32 : 1, /* support of 32 bit transfers */ reladdr : 1; /* Relative addressing support */ u_char vid[8]; /* Vendor ID. [8-15] */ u_char pid[16]; /* Product ID. [16-31] */ u_char revlevel[4]; /* Revision level. [32-35] */} ALL_INQ_DATA;typedef struct dir_read_cap_data { u_char lbn3; /* MSB of number of logical blocks */ u_char lbn2; /* MID HIGH of number of logical blocks */ u_char lbn1; /* MID LOW of number of logical blocks */ u_char lbn0; /* LSB of number of logical blocks */ u_char block_len3; /* MSB of block length in bytes */ u_char block_len2; /* MID HIGH of block length in bytes */ u_char block_len1; /* MID LOW of block length in bytes */ u_char block_len0; /* MSB of block length in bytes */}DIR_READ_CAP_DATA;/* Defined these for magic disk and/or magic disk sector * * #define MAGIC_CTRL * #define MAGIC_UNIT * #define MAGIC_DISK_SECTOR * */extern int inCellMode;/****************** This section is checkpoint stuff ****************/typedef struct Sector { char data[SectorSize]; struct Sector* next;} Sector;typedef struct{ /* Stuff from this point on are stats for the "disk" file */ char filename[128]; /* Name of hd file checkpoint is based on */ char diskname[128]; /* DISK<node>.<ctrl>.<unit> */ off_t fileSize; /* For consistency check of the hd file */ time_t modifyTime; /* the checkpoint is based on */ bool writeable; /* Record whether disk is read-write */ bool doCheckSum; /* Boolean flag if checksum is done */ int checkSum; /* This is not used currently */ int modifyMapSize; /* This is the bitmap used to mark the modified */ char *modifyMap; /* sectors in the mmapped image of the hd file */ Sector *modifiedSectors;/* To store changes for checkpoint restore */ int dfd; /* Actual diskfile */ int sfd; /* Shadow file for changes to COW disk */ int *shadowOffset; /* Offset array into shadow file */ unsigned long nextWriteOffset; /* offset to write to in shadow file */} SimhdSaveInfo;typedef struct { int accessed; /* This is int in case we have > 8 hd's */ SimhdSaveInfo simhdStats;} HdcptData;/****************** End section for checkpoint stuff ****************/typedef struct Device { unsigned char cmd[SIM_DISK_CMD_SIZE]; /* SCSI command */ int isRead; /* TRUE if read request, FALSE if write. */ int64 sizeInSectors; /* transfer size in sectors. */ int64 sectorNum; /* disk address (sector number) */ int done; /* 0 => no transfer in progress * 1 => disk transfer pending */ int bytesTransferred; /* Return value from operation. */ int errnoVal; PA pAddr[SIM_DISK_MAX_DMA_LENGTH]; int offset; /* offset for first page */ int isReady; /* TRUE if the disk is ready. */ int inuse; int dmodel_no; /* disk model disk # for this disk */ /* The following is shared data used for checkpointing */ HdcptData hdcpt; /* Data handling */ struct { int diskOwner; int intrCpu; int execCpu; byte dataBuffer[SectorSize]; /* buffer for (real) I/O */ byte *currPtr; /* ptr to NEXT position in buffer */ int64 currSector; /* keeps track of current sec on disk */ } c; DMARequest dmaReq; /* DMA request area */} Device;static Device**** dks; /* disk data structures [node][ctrl][unit] */static int nnode; /* number of nodes */static int* nctrl; /* number of disks controllers[node] */static int** nunit; /* number of disk units[node][controller] */static void (*int_f)(int node,int ctrl,int unit,int on); /* int fct */static int dmodel_next; /* next free disk model disk number */static int*** inFixedLatency;/* */static int performingSimpleIO = 0;#define DKS(_NODE,_CTRL,_UNIT) \ (*dks[_NODE][_CTRL][_UNIT])#define DKS_filename(_NODE,_CTRL,_UNIT) \ (dks[_NODE][_CTRL][_UNIT]->hdcpt.simhdStats.filename)#define DKS_diskname(_NODE,_CTRL,_UNIT) \ (dks[_NODE][_CTRL][_UNIT]->hdcpt.simhdStats.diskname)extern char *DevFileDir;extern char *MemFileDir;static int SimhdFindSector(int node, int ctrl, int unit, int64 sectorNum, int *fd, unsigned long *offset, int isRead);static int SimhdSetupModifyMap(int node, int ctrl, int unit);static void DMATransfer ( int len, SimTime finishTime, void (*done)(int), int encoded_ctrl_unit);static void DiskDoneRoutine(int encoded_ctrl_unit);static void FixedLatencyDisk(int encoded_ctrl_unit);static void SimhdInitDisks(int restoreFromChkpt);static void SimhdDoCmd(int node, int ctrl, int unit);static void DoScsiCmd(int node, int ctrl, int unit);static int DiskCheckpointCB(CptDescriptor *cptd);static long DetermineDeviceSize(int fd);/*****************************************************************//* Trace for debugging *//* #define DEBUG_HD */#define DEBUG_DMA#ifdef DEBUG_HDstatic char errbuf[32];static void Sim_Warning_NOCR(char *fmt, ...){ va_list args; va_start(args, fmt); vsprintf(errbuf, fmt, args); write(1, errbuf, strlen(errbuf));} static int dotrace = 1;#define DTRACE(c,node,ctrl,unit) \ if (dotrace) {Sim_Warning_NOCR("<%c%d.%d.%d>", c, node,ctrl,unit);}#else#define DTRACE(c,node,ctrl,unit)#endif/*****************************************************************/int rmtdiskfd = -1;voidsim_disk_init(int nodes, int uc, void (*int_fun)(int node, int ctrl, int unit, int on), int restoreFromChkpt){ int n, c; char name[32]; nnode = nodes; /* allocate storage for disk shadow data structures */ dks = (Device****) ZMALLOC(nnode*sizeof(Device***), "dks"); inFixedLatency = (int***) ZMALLOC(nnode*sizeof(int**),"inFixedLatency"); nctrl = (int*) ZMALLOC(nnode*sizeof(int), "nctrl"); nunit = (int**) ZMALLOC(nnode*sizeof(int*), "nunit"); for (n = 0; n < nnode; n++) { if (n >= TOTAL_CPUS) { /* XXX for compatibility with DISCO. Remove later XXX */ nctrl[n] = 1; } else { nctrl[n] = NUM_DISK_CONTROLLERS(M_FROM_CPU(n), MCPU_FROM_CPU(n)); } sprintf(name, "inFixedLatency[%d]", n); inFixedLatency[n] = (int**) ZMALLOC(nctrl[n]*sizeof(int*), name); ASSERT(inFixedLatency[n]); sprintf(name, "nunit[%d]", n); nunit[n] = (int*) ZMALLOC(sizeof(int), name); ASSERT(nunit[n]); for (c = 0; c < nctrl[n]; c++) { nunit[n][c] = uc; sprintf(name, "inFixedLatency[%d][%d]", n, c); inFixedLatency[n][c] = (int*) ZMALLOC(nunit[n][c]*sizeof(int), name); ASSERT(inFixedLatency[n][c]); } } int_f = int_fun; /* register diskdev files */ Simcpt_Register("diskdev", DiskCheckpointCB, ALL_CPUS); /* Do any per disk initialization */ SimhdInitDisks(restoreFromChkpt);}static voiddisk_name(int node, int ctrl, int unit){ if (!DKS_diskname(node,ctrl,unit)[0]) { /* * This disk has not been opened yet, need a name for * the disk file. Try to generate a name in Tcl. */ char* filename = TclDiskFileName(M_FROM_CPU(node), /* machine */ MCPU_FROM_CPU(node), /* node */ ctrl, unit); if (filename) { /* got a name from Tcl (includes path) */ strcpy(DKS_filename(node,ctrl,unit), filename); } else { /* default */ sprintf(DKS_filename(node,ctrl,unit), "%s/DISK%d.%d.%d", DevFileDir, node, ctrl, unit); } /* diskname is an internal id (also used in the log) */ sprintf(DKS_diskname(node,ctrl,unit), "DISK%d.%d.%d", node, ctrl, unit); }}voidsim_disk_touch(int node, int ctrl, int unit){ char name[32]; ASSERT(0 <= node && node < nnode && 0 <= ctrl && ctrl < nctrl[node] && 0 <= unit && unit < nunit[node][ctrl] && dmodel_next < SIM_MAX_DISKS); if (!dks[node]) { /* node touches a disk for the first time */ sprintf(name, "dks[%d]", node); dks[node] = (Device***) ZMALLOC(nctrl[node]*sizeof(Device**), name); ASSERT(dks[node]); } if (!dks[node][ctrl]) { /* controller used for the first time */ sprintf(name, "dks[%d][%d]", node, ctrl); dks[node][ctrl] = (Device**) ZMALLOC(nunit[node][ctrl]*sizeof(Device*), name); ASSERT(dks[node][ctrl]); } /* The following test will fail (eg. unit will already * be 'touched') if we have restored from a checkpoint. * The checkpoint restore code has to allocate the disk * data structures in order to restore them, but the shadow * structures in simmagic aren't yet initialized so it will * call through to here on the first use by the OS. */ if (!dks[node][ctrl][unit]) { sprintf(name, "dks[%d][%d][%d]", node, ctrl, unit); dks[node][ctrl][unit] = (Device*) ZMALLOC(sizeof(Device), name); ASSERT(&DKS(node,ctrl,unit)); /* initialize newly allocated Device */ DKS(node,ctrl,unit).hdcpt.simhdStats.dfd = -1; DKS(node,ctrl,unit).isReady = 1; DKS(node,ctrl,unit).hdcpt.accessed = 0; DKS(node,ctrl,unit).dmodel_no = dmodel_next++; disk_name(node, ctrl, unit); /* generate names */ /* Sim_Warning("dks[%d][%d][%d] model entry %d.\n", node, ctrl, unit, DKS(node,ctrl,unit).dmodel_no); */ }}/* * Do any necessary per disk initialization */static void SimhdInitDisks(int restoreFromChkpt){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -