📄 ahc.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 <malloc.h>#include <stdio.h>#include <string.h>#include <values.h>#include "sim_main/simsys.h"#include "sim_main/util.h"#include "sim_main/evlst.h"#include "Processor/pagetable.h"#include "Caches/req.h"#include "Bus/bus.h"#include "IO/addr_map.h"#include "IO/ahc.h"#include "IO/scsi_bus.h"#include "IO/scsi_controller.h"#include "IO/io_generic.h"#include "../../lamix/dev/ic/aic7xxxreg.h"#include "../../lamix/dev/pci/pcireg.h"typedef unsigned char u_int8_t;#include "../../lamix/dev/scsipi/scsi_all.h"#include "../../lamix/dev/scsipi/scsipi_all.h"#include "../../lamix/dev/scsipi/scsi_disk.h"#include "../../lamix/dev/scsipi/scsipi_disk.h"#define min(a, b) ((a) > (b) ? (b) : (a))/*=========================================================================*//* This structure contains the handles for the generic SCSI controller to *//* communicate with the Adaptec model. */SCSI_CONTROLLER_SPEC ahc_spec ={ ahc_host_read, ahc_host_write, ahc_pci_map, ahc_scsi_wonbus, ahc_scsi_request, ahc_scsi_response, ahc_print_params, ahc_stat_report, ahc_stat_clear, ahc_dump};/*=========================================================================*//* Initialize Adaptec SCSI Controller: allocate control structure, allocate*//* control registers and SCB array, create sequencer event and initialize. *//*=========================================================================*/void ahc_init(SCSI_CONTROLLER *pscsi, int scsi_id){ ahc_t *ahc; int scbs; scbs = MAX_SCBS_DEFAULT; get_parameter("AHC_scbs", &scbs, PARAM_INT); /* allocate internal data structures ------------------------------------*/ ahc = malloc(sizeof(ahc_t)); if (ahc == NULL) YS__errmsg(pscsi->nodeid, "Malloc failed at %s:%i", __FILE__, __LINE__); memset(ahc, 0, sizeof(ahc_t)); ahc->scsi_me = pscsi; ahc->scsi_id = scsi_id; ahc->max_scbs = scbs; ahc->base_addr = 0; pscsi->contr_spec = &ahc_spec; pscsi->controller = ahc; ahc->regs = malloc(AHC_REG_END); if (ahc->regs == NULL) YS__errmsg(pscsi->nodeid, "Malloc failed at %s:%i", __FILE__, __LINE__); memset(ahc->regs, 0, AHC_REG_END); ahc->scbs = malloc(sizeof(ahc_scb_t) * ahc->max_scbs); if (ahc->scbs == NULL) YS__errmsg(pscsi->nodeid, "Malloc failed at %s:%i", __FILE__, __LINE__); memset(ahc->scbs, 0, sizeof(ahc_scb_t) * ahc->max_scbs); ahc->pending = malloc(sizeof(ahc_scb_t*) * SCSI_WIDTH * 8); if (ahc->pending == NULL) YS__errmsg(pscsi->nodeid, "Malloc failed at %s:%i", __FILE__, __LINE__); memset(ahc->pending, 0, sizeof(ahc_scb_t*) * SCSI_WIDTH * 8); /* create sequencer event -----------------------------------------------*/ ahc->seq_cycle_read = ((1000000/SCSI_FREQUENCY) / CPU_CLK_PERIOD) * (ARCH_linesz2/SCSI_WIDTH); ahc->seq_cycle_write = (int)((double)ahc->seq_cycle_read*0.98); ahc->seq_cycle_fast = BUS_FREQUENCY * 2; ahc->seq_state = SEQ_IDLE; ahc->sequencer = NewEvent("AHC SCSI Sequencer", ahc_sequencer, NODELETE, 0); EventSetArg(ahc->sequencer, ahc, sizeof(ahc)); /* initialize (reset) control registers and statistics ------------------*/ ahc_reset(ahc); ahc_stat_clear(ahc);}/*=========================================================================*//* Reset internal data structures. Called during initialization and upon *//* software reset (write to reset register). *//* Clear all registers, return sequencer to idle state and reset SCB *//* queues. Probably not safe during normal operation. *//*=========================================================================*/void ahc_reset(ahc_t *ahc){ memset(ahc->regs, 0, AHC_REG_END); ahc->seq_state = SEQ_IDLE; ahc->seq_pause = 1; ahc->seq_scb = 0; if (IsScheduled(ahc->sequencer)) deschedule_event(ahc->sequencer); ahc_queue_init(ahc->qin_fifo); ahc_queue_init(ahc->qout_fifo); ahc_queue_init(ahc->reconnect_scbs); ahc->regs[SCSIID] = ahc->scsi_id; ahc->regs[SCSICONF] = ahc->scsi_id; ahc->regs[SCSICONF+1] = ahc->scsi_id; ahc->regs[DISC_DSB_A] = 0x00; ahc->regs[DISC_DSB_B] = 0x00; ahc->regs[WAITING_SCBH] = SCB_LIST_NULL; ahc->regs[TARG_SCRATCH+0x10] = ahc->scsi_me->scsi_max_target; ahc->regs[TARG_SCRATCH+0x11] = ahc->scsi_me->scsi_max_lun; if (SCSI_WIDTH > 1) ahc->regs[SBLKCTL] = SELWIDE; else ahc->regs[SBLKCTL] = 0; ahc->regs[HCNTRL] = PAUSE | CHIPRSTACK;}/*=========================================================================*//* Callback routine for host bus reads. Shift SCB output queue upon read *//* from head and collect statistics for interrupt status reads. *//*=========================================================================*/int ahc_host_read(void *controller, unsigned address, unsigned length){ ahc_t *ahc = (ahc_t*)controller; unsigned char *regs, data; unsigned offset; double lat; if ((address < ahc->base_addr) || (address >= ahc->base_addr + AHC_REG_END)) { YS__warnmsg(ahc->scsi_me->nodeid, "AHC: Read from invalid address 0x%08X\n", address); return(1); } offset = address - ahc->base_addr; regs = ahc->regs; /* handle each byte that is read by the request individually ------------*/ for (; length > 0; offset++, length--) {#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] AHC Read 0x%03X %i -> 0x%02X\n", ahc->scsi_me->mid, offset, length, ahc->regs[offset]);#endif switch(offset) { /*---------------------------------------------------------------*/ /* read from SCB output queue: shift queue and adjust counter */ case QOUTFIFO: ahc_queue_shiftout(ahc->qout_fifo, data); regs[QOUTCNT] = ahc_queue_size(ahc->qout_fifo); regs[QOUTFIFO] = ahc_queue_head(ahc->qout_fifo); lat = YS__Simtime - ahc->scbs[data].start_time; if (lat > ahc->request_total_time_max) ahc->request_total_time_max = lat; if (lat < ahc->request_total_time_min) ahc->request_total_time_min = lat; ahc->request_total_time_avg += lat; break; /*---------------------------------------------------------------*/ /* read from interrupt status: record latency for first read */ case INTSTAT: if (!ahc->intr_seq_lat_done) { lat = YS__Simtime - ahc->intr_seq_start; ahc->intr_seq_lat_avg += lat; if (lat > ahc->intr_seq_lat_max) ahc->intr_seq_lat_max = lat; if (lat < ahc->intr_seq_lat_min) ahc->intr_seq_lat_min = lat; ahc->intr_seq_lat_done = 1; } if (!ahc->intr_cmpl_lat_done) { lat = YS__Simtime - ahc->intr_cmpl_start; ahc->intr_cmpl_lat_avg += lat; if (lat > ahc->intr_cmpl_lat_max) ahc->intr_cmpl_lat_max = lat; if (lat < ahc->intr_cmpl_lat_min) ahc->intr_cmpl_lat_min = lat; ahc->intr_cmpl_lat_done = 1; } if (!ahc->intr_scsi_lat_done) { lat = YS__Simtime - ahc->intr_scsi_start; ahc->intr_scsi_lat_avg += lat; if (lat > ahc->intr_scsi_lat_max) ahc->intr_scsi_lat_max = lat; if (lat < ahc->intr_scsi_lat_min) ahc->intr_scsi_lat_min = lat; ahc->intr_scsi_lat_done = 1; } break; } } return(1);}/*=========================================================================*//* Callback routine for host bus writes. *//* Handle side-effects and statistics. *//*=========================================================================*/int ahc_host_write(void *controller, unsigned address, unsigned length){ unsigned char data, *regs; unsigned olength = length; ahc_t *ahc = (ahc_t*)controller; unsigned offset; double lat; if ((address < ahc->base_addr) || (address >= ahc->base_addr + AHC_REG_END)) { YS__warnmsg(ahc->scsi_me->nodeid, "AHC: Read from invalid address 0x%08X\n", address); return(1); } offset = address - ahc->base_addr; regs = ahc->regs; /* handle each byte that is affected by the request individually --------*/ for (; length > 0; offset++, length--) { data = regs[offset];#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] AHC Write 0x%03X %i -> 0x%02X\n", ahc->scsi_me->mid, offset, length, data);#endif switch (offset) { /*---------------------------------------------------------------*/ /* change SCB pointer: copy new SCB entry into register set */ case SCBPTR: data %= ahc->max_scbs; memcpy(regs + SCBARRAY, &ahc->scbs[data], AHC_REG_END - SCBARRAY);#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] Change SCB Pointer to %i\n", ahc->scsi_me->mid, data);#endif regs[SCBPTR] = data; break; /*---------------------------------------------------------------*/ /* host control write: start or stop sequencer, perform reset */ case HCNTRL: if (data & PAUSE) /* pause bit set: halt sequencer */ { ahc->seq_pause = 1;#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] Pause Sequencer\n", ahc->scsi_me->mid);#endif } if (!(data & PAUSE) && /* pause bit cleared: start seq. */ (ahc->seq_pause)) {#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] UnPause Sequencer\n", ahc->scsi_me->mid);#endif if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); ahc->seq_pause = 0; } if (data & CHIPRST) /* reset bit set: perform reset */ {#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] Reset AHC\n", ahc->scsi_me->mid);#endif ahc_reset(ahc); regs[HCNTRL] = CHIPRSTACK; } break; /*---------------------------------------------------------------*/ /* clear SCSI interrupt status 0 (write only) */ case CLRSINT0: regs[CLRSINT0] &= ~data; /* clear register */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -