📄 scsi_disk.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 <string.h>#include <values.h>#include <math.h>#include "sim_main/simsys.h"#include "sim_main/util.h"#include "sim_main/evlst.h"#include "Processor/simio.h"#include "Caches/system.h"#include "Caches/lqueue.h"#include "IO/scsi_bus.h"#include "IO/scsi_disk.h"#include "IO/pci.h"#ifndef linuxtypedef unsigned char u_int8_t;#endif#include "../../lamix/dev/scsipi/scsipi_all.h"#define min(a, b) ((a) > (b) ? (b) : (a))void DISK_request_handler ();void DISK_seek_handler ();void DISK_sector_handler ();int DISK_issue_request (SCSI_DISK *pdisk, SCSI_REQ* req);void DISK_wonbus (void*, SCSI_REQ*);void DISK_request (void*, SCSI_REQ*);void DISK_response (void*, SCSI_REQ*);void DISK_perform (void*, SCSI_REQ*);void DISK_stat_report (void*);void DISK_stat_clear (void*);void DISK_dump (void*);/*=========================================================================*//* Create and configure a SCSI disk module *//* Allocate and initialize a new disk drive control structure. Redirect *//* configuration file if a separate disk-config file is specified, and *//* read parameters. Restore original configuration file name. Allocate and *//* initialize queues, cache and persistent storage. Attach to SCSI bus. *//*=========================================================================*/void SCSI_disk_init(SCSI_BUS *psbus, int dev_id){ SCSI_DISK *pdisk; char seek_method[128]; char disk_configfile[PATH_MAX]; char *old_configfile; extern FILE *pfp; extern char *configfile; int n; pdisk = (SCSI_DISK*)malloc(sizeof(SCSI_DISK)); if (pdisk == NULL) YS__errmsg(psbus->node_id, "Malloc failed at %s:%i", __FILE__, __LINE__); pdisk->dev_id = dev_id; pdisk->current_cylinder = 0; pdisk->current_head = 0; /*-----------------------------------------------------------------------*/ strcpy(pdisk->name, "IBM/Ultrastar_9LP"); pdisk->seek_single = 0.7; pdisk->seek_avg = 6.5; pdisk->seek_full = 14.0; pdisk->seek_method = DISK_SEEK_CURVE; pdisk->write_settle = 1.3; pdisk->head_switch = 0.85; pdisk->cntl_overhead = 40; pdisk->rpm = 7200; pdisk->cylinders = 8420; pdisk->heads = 10; pdisk->sectors = 209; pdisk->cylinder_skew = 20; pdisk->track_skew = 35; pdisk->request_queue_size = 32; pdisk->response_queue_size = 32; pdisk->cache_size = 1024; pdisk->cache_segments = 16; pdisk->cache_write_segments = 2; pdisk->prefetch = 1; pdisk->fast_writes = 0; pdisk->buffer_full_ratio = 0.75; pdisk->buffer_empty_ratio = 0.75; pdisk->ticks_per_ms = 1000000000 / CPU_CLK_PERIOD; /*-----------------------------------------------------------------------*/ pdisk->scsi_me = SCSI_device_init(psbus, dev_id, pdisk, DISK_wonbus, DISK_request, DISK_response, DISK_perform, DISK_stat_report, DISK_stat_clear, DISK_dump); /*-----------------------------------------------------------------------*/ strcpy(disk_configfile, ""); get_parameter("DISK_params", disk_configfile, PARAM_STRING); if (strlen(disk_configfile) > 0) { fclose(pfp); pfp = NULL; old_configfile = configfile; configfile = disk_configfile; } get_parameter("DISK_name", &(pdisk->name), PARAM_STRING); get_parameter("DISK_seek_single", &(pdisk->seek_single), PARAM_DOUBLE); get_parameter("DISK_seek_av", &(pdisk->seek_avg), PARAM_DOUBLE); get_parameter("DISK_seek_full", &(pdisk->seek_full), PARAM_DOUBLE); strcpy(seek_method, ""); get_parameter("DISK_seek_method", seek_method, PARAM_STRING); if (strncasecmp("DISK_SEEK_NONE", seek_method, 14) == 0) pdisk->seek_method = DISK_SEEK_NONE; if (strncasecmp("DISK_SEEK_CONST", seek_method, 15) == 0) pdisk->seek_method = DISK_SEEK_CONST; if (strncasecmp("DISK_SEEK_LINE", seek_method, 14) == 0) pdisk->seek_method = DISK_SEEK_LINE; if (strncasecmp("DISK_SEEK_CURVE", seek_method, 15) == 0) pdisk->seek_method = DISK_SEEK_CURVE; get_parameter("DISK_write_settle", &(pdisk->write_settle), PARAM_DOUBLE); get_parameter("DISK_head_switch", &(pdisk->head_switch), PARAM_DOUBLE); get_parameter("DISK_cntl_ov", &(pdisk->cntl_overhead), PARAM_DOUBLE); get_parameter("DISK_rpm", &(pdisk->rpm), PARAM_INT); get_parameter("DISK_cyl", &(pdisk->cylinders), PARAM_INT); get_parameter("DISK_heads", &(pdisk->heads), PARAM_INT); get_parameter("DISK_sect", &(pdisk->sectors), PARAM_INT); get_parameter("DISK_cylinder_skew", &(pdisk->cylinder_skew), PARAM_INT); get_parameter("DISK_track_skew", &(pdisk->track_skew), PARAM_INT); get_parameter("DISK_request_q", &(pdisk->request_queue_size), PARAM_INT); get_parameter("DISK_response_q", &(pdisk->response_queue_size),PARAM_INT); get_parameter("DISK_cache_size", &(pdisk->cache_size), PARAM_INT); get_parameter("DISK_cache_seg", &(pdisk->cache_segments), PARAM_INT); get_parameter("DISK_cache_write_seg", &(pdisk->cache_write_segments), PARAM_INT); get_parameter("DISK_prefetch" , &(pdisk->prefetch) , PARAM_INT); get_parameter("DISK_fast_write", &(pdisk->fast_writes), PARAM_INT); get_parameter("DISK_buffer_full", &(pdisk->buffer_full_ratio), PARAM_DOUBLE); get_parameter("DISK_buffer_empty",&(pdisk->buffer_empty_ratio), PARAM_DOUBLE); if (pdisk->cache_size != ToPowerOf2(pdisk->cache_size)) YS__errmsg(psbus->node_id, "DISK: Size of disk cache must be power of two"); if (pdisk->cache_segments != ToPowerOf2(pdisk->cache_segments)) YS__errmsg(psbus->node_id, "DISK: Number of disksegments must be power of two"); if (strlen(disk_configfile) > 0) { fclose(pfp); pfp = NULL; configfile = old_configfile; } /*-----------------------------------------------------------------------*/ lqueue_init(&(pdisk->inqueue), pdisk->request_queue_size); lqueue_init(&(pdisk->outqueue), pdisk->response_queue_size); pdisk->state = DISK_IDLE; pdisk->current_req = NULL; pdisk->start_offset = (pdisk->scsi_me->scsi_bus->node_id * SCSI_WIDTH * 8 * PCI_MAX_DEVICES) + (pdisk->scsi_me->scsi_bus->bus_id * SCSI_WIDTH * 8) + pdisk->scsi_me->dev_id; pdisk->start_offset %= pdisk->sectors; pdisk->request_event = NewEvent("Disk Request", DISK_request_handler, NODELETE, 0); EventSetArg(pdisk->request_event, (char*)pdisk, sizeof(pdisk)); pdisk->seek_event = NewEvent("Disk Sector Reached", DISK_seek_handler, NODELETE, 0); EventSetArg(pdisk->seek_event, (char*)pdisk, sizeof(pdisk)); pdisk->sector_event = NewEvent("Disk Sector Transferred", DISK_sector_handler, NODELETE, 0); EventSetArg(pdisk->sector_event, (char*)pdisk, sizeof(pdisk)); DISK_storage_init(pdisk); DISK_cache_init(pdisk); DISK_stat_clear(pdisk); /*-----------------------------------------------------------------------*/ /* initialize inquiry data command return structure */ memset(&pdisk->inquiry_data, 0, sizeof(pdisk->inquiry_data)); pdisk->inquiry_data.type = SCSI_DEVICE_DISK; pdisk->inquiry_data.qualifier = 0; pdisk->inquiry_data.version = 2; pdisk->inquiry_data.response_format = 0; pdisk->inquiry_data.additional_length = sizeof(SCSI_INQUIRY_DATA) - 4; pdisk->inquiry_data.flags = SID_CmdQue | SID_Linked | SID_WBus16 | SID_WBus32; n = strcspn(pdisk->name, "/"); if ((n > sizeof(pdisk->inquiry_data.vendor) - 1) || (n == 0)) strcpy(pdisk->inquiry_data.vendor, "Unknown"); else strncpy(pdisk->inquiry_data.vendor, pdisk->name, n); n += strspn(pdisk->name + n, "/"); strncpy(pdisk->inquiry_data.product, pdisk->name + n, min(sizeof(pdisk->inquiry_data.product) - 1, strlen(pdisk->name + n))); strcpy(pdisk->inquiry_data.revision, "1.0"); /*-----------------------------------------------------------------------*/ /* initialize mode sense command return structure */ memset(&pdisk->mode_sense_data, 0, sizeof(pdisk->mode_sense_data)); pdisk->mode_sense_data.data_length = sizeof(pdisk->mode_sense_data) - 1; pdisk->mode_sense_data.medium_type = 0; pdisk->mode_sense_data.blk_desc_length = 8; pdisk->mode_sense_data.density = 0; n = pdisk->cylinders * pdisk->heads * pdisk->sectors; pdisk->mode_sense_data.nblocks[0] = (n >> 16) & 0xFF; pdisk->mode_sense_data.nblocks[1] = (n >> 8) & 0xFF; pdisk->mode_sense_data.nblocks[2] = n & 0xFF; pdisk->mode_sense_data.blklen[0] = (SCSI_BLOCK_SIZE >> 16) & 0xFF; pdisk->mode_sense_data.blklen[1] = (SCSI_BLOCK_SIZE >> 8) & 0xFF; pdisk->mode_sense_data.blklen[2] = SCSI_BLOCK_SIZE & 0xFF; pdisk->mode_sense_data.page_code = 4; pdisk->mode_sense_data.page_length = 22; pdisk->mode_sense_data.disk_pages.rigid_geometry.ncyl[0] = (pdisk->cylinders >> 16) & 0xFF; pdisk->mode_sense_data.disk_pages.rigid_geometry.ncyl[1] = (pdisk->cylinders >> 8) & 0xFF; pdisk->mode_sense_data.disk_pages.rigid_geometry.ncyl[2] = pdisk->cylinders & 0xFF; pdisk->mode_sense_data.disk_pages.rigid_geometry.nheads = pdisk->heads; pdisk->mode_sense_data.disk_pages.rigid_geometry.rpm[0] = (pdisk->rpm >> 8) & 0xFF; pdisk->mode_sense_data.disk_pages.rigid_geometry.rpm[1] = pdisk->rpm & 0xFF; /*-----------------------------------------------------------------------*/ /* allocate sense data return structure array - one per initiator */ pdisk->sense_data = (SCSI_EXT_SENSE_DATA*)malloc(sizeof(SCSI_EXT_SENSE_DATA) * SCSI_WIDTH * 8);}/*=========================================================================*//* Event handler for incoming requests: takes requests off the input *//* queue, checks for cache hits, attaches a cache segment to the request *//* and starts a seek operation if necessary. *//* Event is scheduled by 'disk_request' when a new request enters an empty *//* qeueue and the disk is idle, by itself when a request is completed, by *//* the seek event handler when a seek request is completed or by the *//* sector event all sectors are transferred. *//*=========================================================================*/void DISK_request_handler(){ SCSI_DISK *pdisk = (SCSI_DISK*)EventGetArg(NULL); SCSI_REQ *req; int start_block; int length, segment; int hit_type; /*=======================================================================*/ /* if queue is empty and fast writes are pending create a write request */ start_block = 0; length = MAXINT; segment = DISK_cache_getwsegment(pdisk, &start_block, &length); if (!lqueue_empty(&pdisk->inqueue)) req = lqueue_head(&pdisk->inqueue); if ((pdisk->fast_writes) && (pdisk->current_req == NULL) && (segment >= 0) && ((lqueue_empty(&pdisk->inqueue)) || ((!lqueue_empty(&pdisk->inqueue)) && (req->orig_request == SCSI_REQ_WRITE) && (req->transferred == 0)))) {#ifdef SCSI_DISK_TRACE YS__logmsg(pdisk->scsi_me->scsi_bus->node_id, "[%i:%i] %0.f: Start Cache Writeback Segment %i\n", pdisk->scsi_me->scsi_bus->bus_id+1, pdisk->scsi_me->dev_id, YS__Simtime, segment);#endif req = (SCSI_REQ*)YS__PoolGetObj(&YS__ScsiReqPool); req->orig_request = SCSI_REQ_WRITE; req->start_block = start_block; req->length = length; req->current_length = 0; req->transferred = length; req->cache_segment = segment; req->imm_flag = SCSI_FLAG_TRUE; req->buscycles = 0; pdisk->current_req = req; } /*=======================================================================*/ /* no current request (could be write-back or prefetch) */ /* get new request from queue */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -