📄 scsi_bus.c
字号:
/* * Copyright (c) 2002 The Board of Trustees of the University of Illinois and * William Marsh Rice University * Copyright (c) 2002 The University of Utah * Copyright (c) 2002 The University of Notre Dame du Lac * * All rights reserved. * * Based on RSIM 1.0, developed by: * Professor Sarita Adve's RSIM research group * University of Illinois at Urbana-Champaign and William Marsh Rice University * http://www.cs.uiuc.edu/rsim and http://www.ece.rice.edu/~rsim/dist.html * ML-RSIM/URSIM extensions by: * The Impulse Research Group, University of Utah * http://www.cs.utah.edu/impulse * Lambert Schaelicke, University of Utah and University of Notre Dame du Lac * http://www.cse.nd.edu/~lambert * Mike Parker, University of Utah * http://www.cs.utah.edu/~map * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal with the Software without restriction, including without * limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, subject to the following * conditions: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimers. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimers in the * documentation and/or other materials provided with the distribution. * 3. Neither the names of Professor Sarita Adve's RSIM research group, * the University of Illinois at Urbana-Champaign, William Marsh Rice * University, nor the names of its contributors may be used to endorse * or promote products derived from this Software without specific prior * written permission. * 4. Neither the names of the ML-RSIM project, the URSIM project, the * Impulse research group, the University of Utah, the University of * Notre Dame du Lac, nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS WITH THE SOFTWARE. *//*---------------------------------------------------------------------------*/#include <stdio.h>#include <stdlib.h>#include "sim_main/simsys.h"#include "sim_main/util.h"#include "Processor/simio.h"#include "Caches/system.h"#include "IO/scsi_bus.h"int SCSI_WIDTH = 2; /* 16 byte SCSI data path */int SCSI_FREQUENCY = 10; /* SCSI bus frequency in MHz */int SCSI_FREQ_RATIO; /* CPU to SCSI frequency ratio */int SCSI_ARB_DELAY = 24; /* arbitration delay in SCSI cycles - 2.4 us */int SCSI_BUS_FREE = 8; /* minimum bus free time in cycles - 800 ns */int SCSI_REQ_DELAY = 13; /* lumped delay for request transfer in cycles */int SCSI_SEL_TIMEOUT = 10000; /* target selection timeout in cycles - 1 ms */const char *SCSI_ReqName[SCSI_REQ_MAX] ={ "MISCELLANEOUS", "INQUIRY ", "MODE SENSE ", "READ CAPACITY", "REQUEST SENSE", "READ ", "WRITE ", "PREFETCH ", "SEEK ", "FORMAT ", "SYNC_CACHE ", "RECONNECT ",};const char *SCSI_RepName[SCSI_REP_MAX] ={ "COMPLETE ", "CONNECT ", "DISCONNECT", "SAVE_D_PTR", "BUSY ", "REJECT ", "TIMEOUT "};void SCSI_bus_arbitrate();void SCSI_bus_send_request();void SCSI_bus_send_response();/*===========================================================================*//* Initialize SCSI subsystem - read parameters *//* Should be called before any other SCSI devices are initialized. *//*===========================================================================*/void SCSI_init(void){ /* note that SCSI_frequency is specified in MHz, not as a ratio. */ /* various delays and latencies are given in SCSI cycles. */ get_parameter("SCSI_width", &SCSI_WIDTH, PARAM_INT); get_parameter("SCSI_frequency", &SCSI_FREQUENCY, PARAM_INT); get_parameter("SCSI_arb_delay", &SCSI_ARB_DELAY, PARAM_INT); get_parameter("SCSI_bus_free", &SCSI_BUS_FREE, PARAM_INT); get_parameter("SCSI_req_delay", &SCSI_REQ_DELAY, PARAM_INT); get_parameter("SCSI_timeout", &SCSI_SEL_TIMEOUT, PARAM_INT); SCSI_FREQ_RATIO = (1000000 / SCSI_FREQUENCY) / CPU_CLK_PERIOD;}/*===========================================================================*//* Initialize a SCSI bus *//* Allocate memory for bus control structure, initialize it, allocate *//* space for N attached devices and create the events. *//*===========================================================================*/SCSI_BUS *SCSI_bus_init(int node_id, int bus_id){ SCSI_BUS *psbus; int n; psbus = (SCSI_BUS*)malloc(sizeof(SCSI_BUS)); if (psbus == NULL) YS__errmsg(node_id, "Malloc failed at %s:%i", __FILE__, __LINE__); psbus->node_id = node_id; psbus->bus_id = bus_id; psbus->state = SCSI_BUS_IDLE; psbus->current_req = NULL; psbus->devices = (SCSI_DEV**)malloc(SCSI_WIDTH * 8 * sizeof(SCSI_DEV*)); if (psbus->devices == NULL) YS__errmsg(node_id, "Malloc failed at %s:%i", __FILE__, __LINE__); for (n = 0; n < SCSI_WIDTH * 8; n++) psbus->devices[n] = NULL; psbus->arbitrate = NewEvent("SCSI Bus Arbitrate", SCSI_bus_arbitrate, NODELETE, 0); EventSetArg(psbus->arbitrate, (char*)psbus, sizeof(psbus)); psbus->send_request = NewEvent("SCSI Bus Send Request", SCSI_bus_send_request, NODELETE, 0); EventSetArg(psbus->send_request, (char*)psbus, sizeof(psbus)); psbus->send_response = NewEvent("SCSI Bus Send Response", SCSI_bus_send_response, NODELETE, 0); EventSetArg(psbus->send_response, (char*)psbus, sizeof(psbus)); psbus->utilization = 0.0; psbus->num_trans = 0; psbus->last_clear = 0.0; return(psbus);}/*===========================================================================*//* Called by the arbitrate-event, which is scheduled when a device *//* arbitrates and the bus is currently idle, or at the end of a transfer. *//* Arbitrate among SCSI devices. Search through list of devices for non-NULL *//* req-pointer, starting at device N-1. First request becomes current. *//* Schedule request event after REQ_DELAY cycles. Writes are delivered *//* even later to account for the data transfer. *//*===========================================================================*/void SCSI_bus_arbitrate(){ SCSI_BUS *psbus = (SCSI_BUS*)EventGetArg(NULL); int n; int delay; for (n = SCSI_WIDTH * 8 - 1; n >= 0; n--) { if (psbus->devices[n] == NULL) continue; if (psbus->devices[n]->req != NULL) { SCSI_REQ *req; psbus->state = SCSI_BUS_BUSY; req = psbus->current_req = psbus->devices[n]->req; delay = 0; if (req->request_type != SCSI_REQ_RECONNECT) { delay = SCSI_REQ_DELAY; schedule_event(psbus->send_request, YS__Simtime + delay * SCSI_FREQ_RATIO); } else { SCSI_REPLY_TYPE old = req->reply_type; /* check if initiator device exists ---------------------------*/ if ((req->initiator < 0) || (req->initiator >= SCSI_WIDTH * 8)) YS__errmsg(psbus->node_id, "SCSI %i.%i: Illegal initiator ID in request at %.1f\n", psbus->node_id, psbus->bus_id, YS__Simtime); if ((psbus->devices[req->initiator] == NULL) || (psbus->devices[req->initiator]->response_callback == NULL)) YS__errmsg(psbus->node_id, "SCSI %i.%i: No response callback registered for module %i\n", psbus->node_id, psbus->bus_id, req->initiator); /* deliver RECONNECT to initiator -----------------------------*/ req->reply_type = SCSI_REP_CONNECT; psbus->devices[req->initiator]->response_callback(psbus->devices[req->initiator]->device, req); req->reply_type = old; delay = psbus->devices[n]->req->buscycles; schedule_event(psbus->send_response, YS__Simtime + delay * SCSI_FREQ_RATIO); } psbus->devices[n]->req = NULL; if (psbus->devices[n]->wonbus_callback != NULL) psbus->devices[n]->wonbus_callback(psbus->devices[n]->device, psbus->current_req); return; } } psbus->state = SCSI_BUS_IDLE;}/*===========================================================================*//* Send a SCSI request to the target. Called by send_request event, which is *//* scheduled by the arbitration routine to occur at the end of the command *//* transfer (including write-data). *//* Schedule a timeout response after TIMEOUT cycles if target device does *//* not exist, or call the devices request callback routine. The callback *//* function modifies the request into a response and returns the number of *//* cycles after which the response should be returned. *//*===========================================================================*/void SCSI_bus_send_request(){ SCSI_BUS *psbus = (SCSI_BUS*)EventGetArg(NULL); SCSI_REQ *req = psbus->current_req; SCSI_REPLY_TYPE old; int delay; /* check if target device exists, timeout if not --------------------------*/ if ((req->target < 0) || (req->target >= SCSI_WIDTH * 8)) YS__errmsg(psbus->node_id, "SCSI %i:%i: Illegal target ID in request at %.1f\n", psbus->node_id, psbus->bus_id, YS__Simtime); if ((psbus->devices[req->target] == NULL) || (psbus->devices[req->target]->request_callback == NULL)) { req->reply_type = SCSI_REP_TIMEOUT; if (IsNotScheduled(psbus->send_response)) schedule_event(psbus->send_response, YS__Simtime + SCSI_SEL_TIMEOUT * SCSI_FREQ_RATIO); return; } /* deliver request to target device, schedule response --------------------*/ psbus->devices[req->target]->request_callback(psbus->devices[req->target]->device, req); /* if request is complete and data is to be transferred, send CONNECT to initiator */ if (((req->reply_type == SCSI_REP_COMPLETE) || (req->reply_type == SCSI_REP_SAVE_DATA_POINTER)) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -