Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / include / disk.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: disk.h
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
#ifndef __DISK_H__
#define __DISK_H__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include "utils.h"
/*-------------------------- vtoc8 disk label -------------------------------*/
// On sparc platform _SUNOS_VTOC_8 is defined whereas on i386 platform
// _SUNOS_VTOC_16 is defined. We want to simulate sparc on i386 and
// cannot simply override these definitions, hence we have to lift vtoc/label
// out of system include files and create our own.
#define LEN_DKL_ASCII 128 /* length of dkl_asciilabel */
#define LEN_DKL_VVOL 8 /* length of v_volume */
#define DK_LABEL_SIZE 512 /* size of disk label */
#define READ_DELAY_DEFAULT 0 /* default disk read delay in microseconds */
#define WRITE_DELAY_DEFAULT 0 /* default disk write delay in microseconds */
/*
* partition headers: section 1
* Fixed size for on-disk dk_label
*/
struct dk_map32 {
int32_t dkl_cylno; /* starting cylinder */
int32_t dkl_nblk; /* number of blocks; if == 0, */
/* partition is undefined */
};
/*
* partition headers: section 2,
* brought over from AT&T SVr4 vtoc structure.
*/
struct dk_map2 {
uint16_t p_tag; /* ID tag of partition */
uint16_t p_flag; /* permission flag */
};
#define VTOC8_NDKMAP 8 /* # of logical partitions */
#define VTOC8_DK_LABEL_LOC 0 /* location of disk label */
struct vtoc8_dk_vtoc {
uint32_t v_version; /* layout version */
char v_volume[LEN_DKL_VVOL]; /* volume name */
uint16_t v_nparts; /* number of partitions */
struct dk_map2 v_part[VTOC8_NDKMAP]; /* partition hdrs, sec 2 */
uint32_t v_bootinfo[3]; /* info needed by mboot */
uint32_t v_sanity; /* to verify vtoc sanity */
uint32_t v_reserved[10]; /* free space */
int32_t v_timestamp[VTOC8_NDKMAP]; /* partition timestamp */
};
#define VTOC8_LEN_DKL_PAD (DK_LABEL_SIZE \
- ((LEN_DKL_ASCII) + \
(sizeof (struct vtoc8_dk_vtoc)) + \
(sizeof (struct dk_map32) * VTOC8_NDKMAP) + \
(14 * (sizeof (uint16_t))) + \
(2 * (sizeof (uint16_t)))))
struct vtoc8_dk_label {
char dkl_ascii_label[LEN_DKL_ASCII]; /* for compatibility */
struct vtoc8_dk_vtoc dkl_vtoc; /* vtoc inclusions from AT&T SVr4 */
uint16_t dkl_write_reinstruct; /* # sectors to skip, writes */
uint16_t dkl_read_reinstruct; /* # sectors to skip, reads */
char dkl_pad[VTOC8_LEN_DKL_PAD]; /* unused part of 512 bytes */
uint16_t dkl_rpm; /* rotations per minute */
uint16_t dkl_pcyl; /* # physical cylinders */
uint16_t dkl_apc; /* alternates per cylinder */
uint16_t dkl_obs1; /* obsolete */
uint16_t dkl_obs2; /* obsolete */
uint16_t dkl_intrlv; /* interleave factor */
uint16_t dkl_ncyl; /* # of data cylinders */
uint16_t dkl_acyl; /* # of alternate cylinders */
uint16_t dkl_nhead; /* # of heads in this partition */
uint16_t dkl_nsect; /* # of 512 byte sectors per track */
uint16_t dkl_obs3; /* obsolete */
uint16_t dkl_obs4; /* obsolete */
struct dk_map32 dkl_map[VTOC8_NDKMAP]; /* logical partition headers */
uint16_t dkl_magic; /* identifies this label format */
uint16_t dkl_cksum; /* xor checksum of sector */
};
/*---------------------------------------------------------------------------*/
#include <stdio.h>
#include <assert.h>
#include <strings.h>
#include <math.h>
#include <errno.h>
#include "ui.h"
#include <list>
extern "C" char *overlaydir;
class bitset{
uint64_t size;
uint64_t map_size;
const char * name;
uint64_t * map;
public:
bitset(uint64_t s,const char *n = 0){
assert(s);
size = s;
map_size = s%64 ? s/64 + 1: s/64;
name = n ? strdup(n):strdup("bitset");
map = new uint64_t[map_size];
assert(map);
for(uint64_t i = 0; i < map_size; i++)
map[i] = 0;
}
~bitset(){ delete map;}
void set(uint64_t pos){
assert(pos < size);
uint64_t index = pos/64;
map[index] |= 1ULL << pos%64;
}
void clear(uint64_t pos){
assert(pos < size);
uint64_t index = pos/64;
map[index] &= ~(1ULL << pos%64);
}
bool get(uint64_t pos){
assert(pos < size);
uint64_t index = pos/64;
return (map[index] >> pos%64) & 0x1;
}
void Or(bitset * s){
assert (s->size == size);
for(uint64_t i = 0; i < map_size; i++ )
map[i] |= s->map[i];
}
void And(bitset * s){
assert (s->size == size);
for(uint64_t i = 0; i < map_size; i++ )
map[i] &= s->map[i];
}
bool dump(FILE * fp){
assert(fp);
if(fwrite((void*)map,map_size * 8, 1, fp) != 1){
fprintf(stderr,"%s: dump failed\n",name);
return false;
}
return true;
}
bool restore(FILE * fp){
assert(fp);
if(fread((void*)map,map_size * 8, 1, fp) != 1){
fprintf(stderr,"%s: restore failed\n",name);
return false;
}
return true;
}
};
struct SCSI_Inquiry_Data { // Inquiry returns this
uint8_t devType; // 0 Device type,
uint8_t devTypeMod; // 1 Device type modifier
uint8_t version; // 2 ISO/ECMA/ANSI version
uint8_t format; // 3 Response data format
uint8_t length; // 4 Additional Length
uint8_t reserved5; // 5 Reserved
uint8_t reserved6; // 6 Reserved
uint8_t flags; // 7 Capability flags
uint8_t vendor[8]; // 8-15 Vendor-specific
uint8_t product[16]; // 16-31 Product id
uint8_t revision[4]; // 32-35 Product revision
uint8_t serialnum[8]; // 36-43 Drive Serial Number
uint8_t vendorSpecific[12];// 36-55 Vendor stuff
uint8_t moreReserved[40]; // 56-95 Reserved
uint8_t copyright[48]; // 96-143 copyright data
SCSI_Inquiry_Data(){
devType = 0x00; /* peripheral type, 0 => disk */
devTypeMod = 0x00; /* zero */
version = 0x02; /* 2 => device commands: SCSI-2 */
format = 0x02; /* 2 => reply format: SCSI-2 */
length = 0x8b; /* page len = number bytes following = (sizeof - 5) */
reserved5 = 0x00; /* feature bits */
reserved6 = 0x00; /* feature bits */
flags = 0x00; /* feature bits */
strncpy((char*)vendor, "YOYODYNE",sizeof(vendor)); /* char VendorID[8] */
strncpy((char*)product,"Turbo Frisbee ",sizeof(product));/* char ProductID[16] */
strncpy((char*)revision,"0000",sizeof(revision)); /* char RevisionID[4] */
strncpy((char*)serialnum," ",sizeof(serialnum)); /* char SerialNumber[8] */
bzero((char*)vendorSpecific, sizeof(vendorSpecific));
bzero((char*)moreReserved, sizeof(moreReserved));
strncpy((char*)copyright, "Copyright (c) 2001 Yoyodyne All rights reserved.",sizeof(copyright));
}
};
struct Supported_VPD{ //0x00
uint8_t devType;
uint8_t pageCode;
uint8_t reserved0;
uint8_t pageLength;
uint8_t pageList[12];
Supported_VPD(){ // by default support all data
devType = 0x0; /* peripheral type */
pageCode = 0x0; /* request code for this reply page */
reserved0 = 0x0;
pageLength = 0xc; /* page len = number bytes following = (sizeof - 4) */
pageList[0] = 0x00; /* Supported Vital Product Data pages */
pageList[1] = 0x80; /* Unit Serial Number page */
pageList[2] = 0x81; /* Implemented Operating Definition page */
pageList[3] = 0x83; /* Device Identification page */
pageList[4] = 0xc0; /* Firmware Numbers page */
pageList[5] = 0xc1; /* Date Code page */
pageList[6] = 0xc2; /* Jumper Settings page */
pageList[7] = 0xc3; /* Device Behaviour page */
pageList[8] = 0xd1; /* Vendor Specific page */
pageList[9] = 0xd2; /* Vendor Specific page */
pageList[10] = 0xd3; /* Vendor Specific page */
pageList[11] = 0xd4; /* Vendor Specific page */
}
};
struct Unit_Serial_Number { // 0x80
uint8_t devType;
uint8_t pageCode;
uint8_t reserved0;
uint8_t pageLength;
uint8_t productSerialNumber[8];
uint8_t boardSerialNumber[12];
Unit_Serial_Number(){
devType = 0x00; /* peripheral type */
pageCode = 0x80; /* request code for this reply page */
reserved0 = 0x00;
pageLength = 0x14; /* page len = number bytes following = (sizeof - 4) */
strncpy((char*)productSerialNumber," ",sizeof(productSerialNumber));
strncpy((char*)boardSerialNumber, " ",sizeof(boardSerialNumber));
}
};
struct Implemented_Operating_Definition{ // 0x81
uint8_t devType;
uint8_t pageCode;
uint8_t reserved0;
uint8_t pageLength;
uint8_t currentOpDef;
uint8_t defaultOpDef[2];
Implemented_Operating_Definition(){
devType = 0x00; /* peripheral type */
pageCode = 0x81; /* request code for this reply page */
reserved0 = 0x00;
pageLength = 0x03; /* page len = number bytes following = (sizeof - 4) */
currentOpDef = 0x01; /* Current Operating Definition, 1 => SCSI-2 */
defaultOpDef[0] = 0x01; /* Default Operating Definition, 1 => SCSI-2 */
defaultOpDef[1] = 0x01; /* Unknown Operating Definition, 1 => SCSI-2 */
}
};
struct Device_Identification{ // 0x83
uint8_t devType;
uint8_t pageCode;
uint8_t reserved0;
uint8_t pageLength;
Device_Identification(){
devType = 0x00; /* peripheral type */
pageCode = 0x83; /* request code for this reply page */
reserved0 = 0x00;
pageLength = 0x00; /* page len = number bytes following = (sizeof - 4) */
}
};
struct FC_Device_Identification:public Device_Identification{
// 0x83
uint8_t codeSet0;
uint8_t idType_Asso0;
uint8_t reserved10;
uint8_t idLength0;
uint8_t id0[8];
uint8_t codeSet1;
uint8_t idType_Asso1;
uint8_t reserved11;
uint8_t idLength1;
uint8_t id1[8];
FC_Device_Identification():Device_Identification(){
codeSet0 = codeSet1 = 0x01; /* code: 1=binary (,2=ascii) */
idType_Asso0 = 0x13; /* assoc: 1=port (,0=node); uid type: 3=NAA */
idType_Asso1 = 0x03; /* assoc: 0=node (,1=port); uid type: 3=NAA */
reserved10 = reserved11 = 0x00;
idLength0 = idLength1 = 0x8;
bzero(id0, sizeof(id0));
bzero(id1, sizeof(id1));
pageLength = 0x18; // override pagelength in base
}
};
// other page codes are not supported.
class Partition{
public:
static const int BYTES_PER_SECTOR = 512;
static const int DISK_PAGE_SIZE = 512; // granularity of r/w to backup/overlay files
// this is chosen same as BYTES_PER_SECTOR to handle/simplify the case of
// overlapping partitions (can be specified by real vtoc's). The disk image
// may not be aligned to a larger mutiple of DISK_PAGE_SIZE which may create
// undetected holes in lblks.
static const int BLOCKS_PER_PAGE = DISK_PAGE_SIZE/BYTES_PER_SECTOR;
int debug_level;
FILE * debug_file;
// Real physical file name or disk partition name in which
// data for the simulated disk partition exists.
const char* part_filename;
// simulated disk partition name
const char* part_name;
// filename of shadow of simulated disk partition in which
// write data is stored. This shadow file is used only when
// the partition is attached read-only which is the default.
const char* overlay_filename;
const char* ckpt_filename;
// if set, write enabled. Otherwise, read only
bool rw;
// true if the parition is an actual host system disk. set from st_rdev of
// the stat buf of part_filename
bool is_device_file;
// this partition has vtoc from the real disk if true
bool has_vtoc;
// size of simulated disk partition in bytes
uint64_t size;
// size of simulated disk partition in logical blocks OR
// the value read from a real vtoc. Can be different from
// size/BYTES_PER_SECTOR
uint64_t nblks;
// starting disk block number of this simulated disk partition
uint64_t start_lblk;
// ending disk block number of this simulated disk partition
uint64_t end_lblk;
// index,flag and tag of this simulated disk partition
int index;
int primary_fd;
int overlay_fd;
int ckpt_fd;
// bitmap of pages in the disk partition that have been modified.
// The modified pages will be in shadow file. The bitmap is used
// only when the partiton is attached read-only which is the default.
uint64_t bitmap_size;
bitset* overlay_bitmap;
bitset* ckpt_bitmap;
Partition();
~Partition();
bool lblk_inrange(uint64_t lblk){
if( (lblk >= start_lblk) && (lblk <= end_lblk) )
return true;
return false;
}
bool create_overlay(const char * dir, const char * disk){
if(rw)
return true; // no need for overlays, partition is rw
// make this function reentrant
if(overlay_bitmap && overlay_fd != -1)
return true;
// create the bitmap where each bit corresponds to 8K size block
// in partition
bitmap_size = (nblks*BYTES_PER_SECTOR + DISK_PAGE_SIZE - 1)/DISK_PAGE_SIZE;
if( overlay_bitmap == 0 )
overlay_bitmap = new bitset(bitmap_size,part_name);
assert(overlay_bitmap);
char buf[1024];
sprintf(buf,"%s/%s.%s.shadow",dir,disk,part_name);
overlay_filename = strdup(buf);
if(overlay_fd == -1)
overlay_fd = open(overlay_filename,O_RDWR|O_CREAT|O_LARGEFILE|O_TRUNC,0666);
if(overlay_fd == -1){
fprintf(debug_file,"%s: could not create overlay file %s\n",\
part_name,overlay_filename);
perror("");
return false;
}
// make the overlay file size a multiple of DISK_PAGE_SIZE
if(lseek(overlay_fd, bitmap_size*DISK_PAGE_SIZE - 1,SEEK_SET) == -1){
fprintf(debug_file,"%s: could not lseek overlay file %s\n",\
part_name,overlay_filename);
perror("");
return false;
}
// set the size of this file
if(write(overlay_fd, "", 1) != 1){
fprintf(debug_file,"%s: could not write overlay file %s\n",\
part_name,overlay_filename);
perror("");
return false;
}
return true;
}
void set_debug_level( int level ){ debug_level = level; }
void set_debug_file( FILE* f ){ debug_file = f; }
void info();
uint32_t Write(uint64_t lblkno, uint8_t *buf, uint32_t numblks);
uint32_t Read(uint64_t lblkno, uint8_t *buf, uint32_t numblks);
bool restore(const char * dir, const char * disk_name);
bool dump(const char * dir, const char * disk_name);
// some statistics
uint64_t lblk_reads;
uint64_t lblk_writes;
uint64_t lblk_reads_primary;
uint64_t lblk_writes_primary;
uint64_t lblk_reads_overlay;
uint64_t lblk_writes_overlay;
uint64_t lblk_reads_ckpt;
};
class Disk{
public:
static const int MAX_TRIES = 10;
static const int BYTES_PER_SECTOR = 512;
static const int MAX_PARTITIONS = 8;
static const int VTOC_SANITY = 0x600ddeee;
static const int DKLABEL_RPM = 5400;
static const int DKLABEL_INTRLV = 1;
static const int DKLABEL_ACYL= 0;
static const int DKLABEL_MAGIC = 0xDABE;
int debug_level;
FILE * debug_file;
char debug_file_name[1024];
protected:
static bool UI_registered;
int target_id;
// disk label structure. Used only if faking a vtoc/disk label
struct vtoc8_dk_label disk_label;
const char * disk_name;
Partition *partitions[MAX_PARTITIONS];
// init the disk label in case of fake vtoc
void label_init();
bool is_s2; // true if disk has a single s2 partition
int num_partitions;
int vtoc_partition; // vtoc partition, in case of real disk vtoc, else -1
bool fake_vtoc; // true if SAM needs to fake vtoc, false otherwise
bool user_geometry;
uint32_t read_delay; // disk read delay
uint32_t write_delay; // disk write delay
// some parameters, useful when faking vtoc
uint16_t sectors_per_track; // dkl_nsect, default 32
uint16_t tracks_per_cylinder; // dkl_nhead, default 16
uint16_t bytes_per_sector; // default 512
uint32_t num_cylinder; // total number of cyinders in disk
uint64_t num_blks; // total number of disk blocks in all partitions
// note capacity command will return
// different value
void set_dkl_cksum(){
int count;
uint16_t *shortp;
uint32_t sum;
sum = 0;
count = sizeof(disk_label) / (int) (sizeof(uint16_t));
#if defined(ARCH_X64)
struct vtoc8_dk_label tmp;
bcopy(&disk_label, &tmp, sizeof(disk_label));
label_endian_convert(&tmp);
shortp = (uint16_t *) &tmp;
while (count--) {
sum ^= ss_byteswap16(*shortp);
shortp++;
}
#else
shortp = (uint16_t *) &disk_label;
while (count--)
sum ^= *shortp++;
#endif
sum = sum & 0x0000FFFF;
disk_label.dkl_cksum = sum;
}
#if defined(ARCH_X64)
void label_endian_convert(struct vtoc8_dk_label *dklp) {
int i;
dklp->dkl_vtoc.v_version = ss_byteswap32(dklp->dkl_vtoc.v_version);
dklp->dkl_vtoc.v_nparts = ss_byteswap16(dklp->dkl_vtoc.v_nparts);
for (i=0;i<VTOC8_NDKMAP;i++) {
dklp->dkl_vtoc.v_part[i].p_tag = ss_byteswap16(dklp->dkl_vtoc.v_part[i].p_tag);
dklp->dkl_vtoc.v_part[i].p_flag = ss_byteswap16(dklp->dkl_vtoc.v_part[i].p_flag);
dklp->dkl_vtoc.v_timestamp[i] = ss_byteswap32(dklp->dkl_vtoc.v_timestamp[i]);
dklp->dkl_map[i].dkl_cylno = ss_byteswap32(dklp->dkl_map[i].dkl_cylno);
dklp->dkl_map[i].dkl_nblk = ss_byteswap32(dklp->dkl_map[i].dkl_nblk);
}
for (i=0;i<3;i++)
dklp->dkl_vtoc.v_bootinfo[i] = ss_byteswap32(dklp->dkl_vtoc.v_bootinfo[i]);
dklp->dkl_vtoc.v_sanity = ss_byteswap32(dklp->dkl_vtoc.v_sanity);
dklp->dkl_write_reinstruct = ss_byteswap16(dklp->dkl_write_reinstruct);
dklp->dkl_read_reinstruct = ss_byteswap16(dklp->dkl_read_reinstruct);
dklp->dkl_rpm = ss_byteswap16(dklp->dkl_rpm);
dklp->dkl_pcyl = ss_byteswap16(dklp->dkl_pcyl);
dklp->dkl_apc = ss_byteswap16(dklp->dkl_apc);
dklp->dkl_intrlv = ss_byteswap16(dklp->dkl_intrlv);
dklp->dkl_ncyl = ss_byteswap16(dklp->dkl_ncyl);
dklp->dkl_acyl = ss_byteswap16(dklp->dkl_acyl);
dklp->dkl_nhead = ss_byteswap16(dklp->dkl_nhead);
dklp->dkl_nsect = ss_byteswap16(dklp->dkl_nsect);
dklp->dkl_magic = ss_byteswap16(dklp->dkl_magic);
dklp->dkl_cksum = ss_byteswap16(dklp->dkl_cksum);
}
#endif
bool dump_misc(const char * dir){
char buf[1024];
sprintf(buf, "%s/%s.miscdmp",dir,disk_name);
FILE * fp = fopen(buf,"w");
if(!fp)
return true;
sprintf(buf,"read_delay %u\n",read_delay);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf,"write_delay %u\n",write_delay);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf,"debug_level %d\n",debug_level);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf,"debug_file_name %s\n",debug_file_name);
fwrite(buf,strlen(buf),1,fp);
for(int i = 0; i < MAX_PARTITIONS; i++){
if(partitions[i]){
sprintf(buf,"Partition %d\n",i);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf," lblk_reads %lld\n",partitions[i]->lblk_reads);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf," lblk_writes %lld\n",partitions[i]->lblk_writes);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf," lblk_reads_primary %lld\n",partitions[i]->lblk_reads_primary);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf," lblk_writes_primary %lld\n",partitions[i]->lblk_writes_primary);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf," lblk_reads_overlay %lld\n",partitions[i]->lblk_reads_overlay);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf," lblk_writes_overlay %lld\n",partitions[i]->lblk_writes_overlay);
fwrite(buf,strlen(buf),1,fp);
sprintf(buf," lblk_reads_ckpt %lld\n",partitions[i]->lblk_reads_ckpt);
fwrite(buf,strlen(buf),1,fp);
}
}
fclose(fp);
return true;
}
bool restore_misc(const char * dir){
char buf[1024], keyword[1024];
sprintf(buf, "%s/%s.miscdmp",dir,disk_name);
FILE * fp = fopen(buf,"r");
if(!fp)
return true;
// support more flexible dump format
while (true) {
fgets(buf,1024,fp);
sscanf(buf,"%s", keyword);
if (!strcmp(keyword, "read_delay"))
sscanf(buf,"%s %u\n",keyword,&read_delay);
else if (!strcmp(keyword, "write_delay"))
sscanf(buf,"%s %u\n",keyword,&write_delay);
else if (!strcmp(keyword, "debug_level"))
sscanf(buf,"%s %d\n",keyword,&debug_level);
else if (!strcmp(keyword, "debug_file_name")){
sscanf(buf,"%s %s\n",keyword,&debug_file_name);
if(!strcmp(debug_file_name,"stderr")){
debug_file = stderr;
}else if(!strcmp(debug_file_name,"stdout")){
debug_file = stdout;
}else
debug_file = fopen(debug_file_name,"w+");
if(!debug_file)
debug_file = stderr;
}
else if (!strcmp(keyword, "Partition"))
break;
}
for(int i = 0; i < MAX_PARTITIONS; i++){
if(partitions[i]){
fgets(buf,1024,fp);
sscanf(buf," lblk_reads %lld\n",&partitions[i]->lblk_reads);
fgets(buf,1024,fp);
sscanf(buf," lblk_writes %lld\n",&partitions[i]->lblk_writes);
fgets(buf,1024,fp);
sscanf(buf," lblk_reads_primary %lld\n",&partitions[i]->lblk_reads_primary);
fgets(buf,1024,fp);
sscanf(buf," lblk_writes_primary %lld\n",&partitions[i]->lblk_writes_primary);
fgets(buf,1024,fp);
sscanf(buf," lblk_reads_overlay %lld\n",&partitions[i]->lblk_reads_overlay);
fgets(buf,1024,fp);
sscanf(buf," lblk_writes_overlay %lld\n",&partitions[i]->lblk_writes_overlay);
fgets(buf,1024,fp);
sscanf(buf," lblk_reads_ckpt %lld\n",&partitions[i]->lblk_reads_ckpt);
}
}
fclose(fp);
return true;
}
// to be called after all partitions have been seen and added
bool add_partition_fini();
bool create_overlays(){
bool ret = true;
for(int i = 0; i < MAX_PARTITIONS; i++)
if(partitions[i])
ret &= partitions[i]->create_overlay(overlaydir,disk_name);
return ret;
}
public:
bool add_partition( int partition, const char * file, bool rw = false, bool has_vtoc = false );
///////// external interface to the gdisk /////////
uint32_t disk_write_lblk( uint64_t lblkno, uint8_t *buf, uint32_t nblks );
uint32_t disk_read_lblk ( uint64_t lblkno, uint8_t *buf, uint32_t nblks );
bool dump( const char * dir );
bool restore( const char * dir );
const char * get_name(){ return disk_name; }
int get_target_id(){ return target_id;}
///////// external interface to the gdisk /////////
void set_name(const char * s){
if(disk_name)
free((void*)disk_name);
disk_name = strdup(s);
}
void set_target(int id){target_id = id;}
int get_num_partitions() { return num_partitions; }
void delete_overlays() {
for(int i = 0; i < MAX_PARTITIONS; i++)
if(partitions[i])
if (partitions[i]->overlay_fd > 0)
close(partitions[i]->overlay_fd);
}
void set_read_delay(uint32_t delay){
read_delay = delay;
}
uint32_t get_read_delay(){
return(read_delay);
}
void set_write_delay(uint32_t delay){
write_delay = delay;
}
uint32_t get_write_delay(){
return(write_delay);
}
// parse string for diskdelay in the form "<rdelay>/<wdelay>"
void parse_ddelay(const char *ddelays, uint32_t *rdelay, uint32_t *wdelay){
char rdelays[100];
strcpy(rdelays, ddelays);
char *wdelays = strchr(rdelays, '/');
if (wdelays){
*wdelays = '\0';
wdelays++; // ptr to write delay
}else{
wdelays = rdelays; // same as read delay
}
*rdelay = atoi(rdelays);
*wdelay = atoi(wdelays);
if (*rdelay & 0x80000000) *rdelay = 0;
if (*wdelay & 0x80000000) *wdelay = 0;
}
void set_disk_delay(const char * s) {
uint32_t rdelay, wdelay;
parse_ddelay(s, &rdelay, &wdelay);
set_read_delay(rdelay);
set_write_delay(wdelay);
}
Disk( const char * name );
~Disk(){}
// UI functions
virtual void display_label();
virtual void display_geometry();
virtual void display_stats();
virtual void display_partitions(int part_num = -1); // -1 displays all
virtual void display_disk_delay();
virtual void set_debug_level(int l);
virtual void set_debug_file(const char * file);
virtual void display_vpd(){}
virtual void display_help();
virtual void handle_ui(int argc, char * argv[]){
if(!strcmp(argv[2],"label")){
display_label();
}
else if(!strcmp(argv[2],"geometry")){
display_geometry();
}else if(!strcmp(argv[2],"stat")){
display_stats();
}else if(!strcmp(argv[2],"partitions")){
if(argv[3]){
int p = strtol(argv[3],0,0);
if( p < 0 || p >= MAX_PARTITIONS){
fprintf(debug_file,"%s Partition number %d out of range\n",disk_name,p);
return;
}
display_partitions(p);
}else
display_partitions(-1);
}else if(!strcmp(argv[2],"vpd")){
display_vpd();
}else if(!strcmp(argv[2],"op")){
if(argv[3])
set_debug_file(argv[3]);
else
fprintf(debug_file," %s\n",debug_file_name);
}else if(!strcmp(argv[2],"debug")){
if(argv[3]){
debug_level = strtol(argv[3],0,0);
set_debug_level(debug_level);
}else
fprintf(debug_file,"%s: debug level %d\n",disk_name,debug_level);
}else if (!strcmp(argv[2],"dd")){
if (argv[3])
set_disk_delay(argv[3]);
else
display_disk_delay();
}else
fprintf(debug_file,"gdisk: unknown command %s\n",argv[2]);
return;
}
};
class SCSIDisk: public Disk{
SCSI_Inquiry_Data sid;
Supported_VPD sv;
Unit_Serial_Number usn;
Implemented_Operating_Definition iod;
Device_Identification di;
FC_Device_Identification fdi;
uint8_t *vendorid; // Drive Standard Inquiry info
int sizeof_vendorid;
uint8_t *productid;
int sizeof_productid;
uint8_t *revisionid;
int sizeof_revisionid;
uint8_t *serialno; // NOTE, Sun Qualified Disks have 12 (not 8) bytes !!!!
int sizeof_serialno;
uint8_t *prodserialno; // Unit Serial Number Inquiry (code 80h) info
int sizeof_prodserialno;
uint8_t *brdserialno;
int sizeof_brdserialno;
uint8_t *portwwn; // Devide Identification Inquiry (code 83h) info
int sizeof_portwwn;
uint8_t *nodewwn;
int sizeof_nodewwn;
void copy(uint8_t * copy_to, int size_to, const char * copy_from){
int size = strlen(copy_from);
if(strlen(copy_from) > size_to){
fprintf(debug_file,"WARNING: string %s longer than %d. Truncated\n",copy_from,size_to);
size = size_to;
}
memset((void*)copy_to,0x20,size_to); // initialize with space chars
bcopy(copy_from,copy_to,size);
}
public:
int Supported_VPD_size;
// external interface to the SCSI/FC Disk. Includes the Disk interface
// functions as well.
SCSIDisk();
~SCSIDisk();
bool parse_config(const char * filename, FILE *, int target = -1);
const char * get_SCSI_Inquiry_Data() { return (const char *) &sid; }
const char * get_Supported_VPD() { return (const char *) &sv; }
const char * get_Unit_Serial_Number() { return (const char *) &usn; }
const char * get_Implemented_Operating_Definition() { return (const char *) &iod; }
const char * get_Device_Identification() { return (const char *) &di; }
const char * get_FC_Device_Identification() { return (const char *) &fdi; }
uint64_t get_capacity() {
uint64_t capacity = disk_label.dkl_ncyl * disk_label.dkl_nhead * disk_label.dkl_nsect;
if(disk_label.dkl_acyl)
capacity += disk_label.dkl_nhead * disk_label.dkl_nsect;
return capacity;
}
//////////////////// end external interface /////////////////////
void set_vendor_id(const char * str){
copy(vendorid,sizeof_vendorid,str);
}
void set_product_id(const char * str){
copy(productid,sizeof_productid,str);
}
void set_revision_id(const char * str){
copy(revisionid,sizeof_revisionid,str);
}
void set_serial_no(const char * str){
copy(serialno,sizeof_serialno,str);
}
void set_prodserial_no(const char * str){
copy(prodserialno,sizeof_prodserialno,str);
}
void set_brdserial_no(const char * str){
copy(brdserialno,sizeof_brdserialno,str);
}
void set_port_wwn(const char * str){
copy(portwwn,sizeof_portwwn,str);
}
void set_node_wwn(const char * str){
copy(nodewwn,sizeof_nodewwn,str);
}
void set_bytes_per_sector(int32_t n){
fprintf(debug_file,"%s: can not change bytes/sector\n",disk_name);
}
void set_sectors_per_track(int32_t n){
if( n > 0xffff){
fprintf(debug_file,"%s: value of sectors/track cannot be larger than 0xffff\n",disk_name);
exit(1);
}else
sectors_per_track = n;
user_geometry = true;
}
void set_tracks_per_cylinder(int32_t n){
if( n > 0xffff){
fprintf(debug_file,"%s: value of tracks/cylinder cannot be larger than 0xffff\n",disk_name);
exit(1);
}else
tracks_per_cylinder = n;
user_geometry = true;
}
// UI functions
void display_vpd();
};
#endif // __DISK_H__