// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: sas.cc
// 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 ============================================
* "sas.cc" LSI SAS1064E PCIE to 4-Port Serial Attached
* SCSI Controller Simulator
* Controller-Host interface
* Copyright (C) 2007 Sun Microsystems, Inc.
// power management capability id register offset
#define PCI_CONF_PM_CAP_ID 0x44
// MSI capability register offset
#define PCI_CONF_MSI_CAP_ID 0x50
// SAS simulator general information
static const char *SAS1064E_Help
= "LSISAS1064E PCI Express to 4-port Serial Attached SCSI Controller";
static const char *SAS1064E_Version
= "1.00";
extern "C" char *overlaydir
;
extern void overlaydir_cleanup();
extern char *get_restore_dir();
SAS::SAS(const char *modname
, const char *instance_name
)
: Module(modname
, instance_name
) {
debug_info("SAS1064E: creating instance %s\n", instance_name
);
_port_enabled
= (uint8_t *)calloc(IOC_NUM_PORTS
, sizeof(uint8_t));
_earliest_serving_time
= (int64_t *)calloc(IOC_NUM_PORTS
, sizeof(int64_t));
_mpt_reg
= (mpt_reg_t
*)calloc(1, sizeof(mpt_reg_t
));
_ioc_conf
= (ioc_conf_t
*)calloc(1, sizeof(ioc_conf_t
));
_hdshk_msg_req_buf
= (uchar_t
*)calloc(1, HDSHK_MSG_SIZE
);
_hdshk_msg_reply_buf
= (uchar_t
*)calloc(1, HDSHK_MSG_SIZE
);
_hdshk_msg_reply_size
= 0;
_hdshk_msg_reply_send
= 0;
while (!_reply_post_queue
.empty())
while (!_reply_free_queue
.empty())
pthread_mutex_init(&_reply_queue_mutex
, NULL
);
// ioc is in ready state after power-on self-initialization
_mpt_reg
->doorbell
= MPI_IOC_STATE_READY
;
debug_info("SAS1064E: deleting instance %s\n", instance_name
);
free(_earliest_serving_time
);
free(_hdshk_msg_req_buf
);
free(_hdshk_msg_reply_buf
);
pthread_mutex_destroy(&_reply_queue_mutex
);
for (int i
= 0; i
< IOC_NUM_PORTS
; i
++) {
_disk
[i
]->delete_overlays();
const char *SAS::get_help() {
return Module::get_help_string();
const char *SAS::get_version() {
bool SAS::parse_arg(const char *arg
) {
if (argval("targets", arg
, &fname
)){
debug_info("%s: targets=<%s>\n", HERE
, fname
);
return dev_parse_arg(arg
);
snprintf(reg_descr
,100,"%s LSISAS1064E Vendor ID", getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,2,0x1000,0x0000,0x0),PCI_CONF_VENID
);
snprintf(reg_descr
,100,"%s LSISAS1064E Device ID", getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,2,0x0056,0x0000,0x0),PCI_CONF_DEVID
);
snprintf(reg_descr
,100,"%s LSISAS1064E Command", getName());
confSpace
->addConfReg(new pcieCommandReg(reg_descr
,(genericPcieDev
*)this,0x0757),PCI_CONF_COMM
);
snprintf(reg_descr
,100,"%s LSISAS1064E Status", getName());
confSpace
->addConfReg(new pcieStatusReg(reg_descr
,(genericPcieDev
*)this,0x0230,0xff38),PCI_CONF_STAT
);
snprintf(reg_descr
,100,"%s LSISAS1064E Rev Id",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x03,0x00),PCI_CONF_REVID
);
snprintf(reg_descr
,100,"%s LSISAS1064E prog class",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0x00),PCI_CONF_PROGCLASS
);
snprintf(reg_descr
,100,"%s LSISAS1064E Sub Class",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0x00),PCI_CONF_SUBCLASS
);
snprintf(reg_descr
,100,"%s LSISAS1064E Base Class",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x01,0x00),PCI_CONF_BASCLASS
);
snprintf(reg_descr
,100,"%s LSISAS1064E Cache Line Size",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0xf8),PCI_CONF_CACHE_LINESZ
);
snprintf(reg_descr
,100,"%s LSISAS1064E Latency Timer",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0xf0),PCI_CONF_LATENCY_TIMER
);
snprintf(reg_descr
,100,"%s LSISAS1064E Header Type",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0x00),PCI_CONF_HEADER
);
snprintf(reg_descr
,100,"%s LSISAS1064E BAR0 - IO",getName());
confSpace
->addConfReg(new pcieBaseAddrReg(reg_descr
,(genericPcieDev
*)this,IO_SIZE
,PCIE_IO
, false, false),PCI_CONF_BASE0
); //256 bytes
snprintf(reg_descr
,100,"%s LSISAS1064E BAR1 MEM64 0",getName());
confSpace
->addConfReg(new pcieBaseAddrReg(reg_descr
,(genericPcieDev
*)this,MEM0_SIZE
,PCIE_MEM
, false, false),PCI_CONF_BASE1
); //1024 bytes
snprintf(reg_descr
,100,"%s LSISAS1064E BAR3 MEM64 1",getName());
confSpace
->addConfReg(new pcieBaseAddrReg(reg_descr
,(genericPcieDev
*)this,MEM1_SIZE
,PCIE_MEM
, false, false),PCI_CONF_BASE3
); //64k bytes
snprintf(reg_descr
,100,"%s LSISAS1064E susbsystem vendor id",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,2,0x0000,0x0000),PCI_CONF_SUBVENID
);
snprintf(reg_descr
,100,"%s LSISAS1064E susbsystem id",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,2,0x0000,0x0000),PCI_CONF_SUBSYSID
);
snprintf(reg_descr
,100,"%s LSISAS1064E ROM base addr",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,4,0x00000000,0x0),PCI_CONF_ROM
);
snprintf(reg_descr
,100,"%s LSISAS1064E capabilities pointer",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,PCI_CONF_PM_CAP_ID
,0x00),PCI_CONF_CAP_PTR
);
snprintf(reg_descr
,100,"%s LSISAS1064E Intr Line",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0xff),PCI_CONF_ILINE
);
snprintf(reg_descr
,100,"%s LSISAS1064E Intr Pin",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x01,0x00),PCI_CONF_IPIN
);
snprintf(reg_descr
,100,"%s LSISAS1064E Min Grant",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0x00),PCI_CONF_MIN_G
);
snprintf(reg_descr
,100,"%s LSISAS1064E Max Lat",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0x00),PCI_CONF_MAX_L
);
// power management capability
snprintf(reg_descr
,100,"%s LSISAS1064E Power Mgmt Cap ID",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x01,0x00),PCI_CONF_PM_CAP_ID
);
snprintf(reg_descr
,100,"%s LSISAS1064E Power Mgmt Next Pointer",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,PCI_CONF_MSI_CAP_ID
,0x00),PCI_CONF_PM_CAP_ID
+PCI_CAP_NEXT_PTR
);
snprintf(reg_descr
,100,"%s LSISAS1064E Power Mgmt Capabilities",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,2,0x0202,0x0000),PCI_CONF_PM_CAP_ID
+PCI_PMCAP
);
snprintf(reg_descr
,100,"%s LSISAS1064E Power Mgmt CSR",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,2,0x0000,0x0000),PCI_CONF_PM_CAP_ID
+PCI_PMCSR
);
snprintf(reg_descr
,100,"%s LSISAS1064E Power Mgmt CSR Bridge Support Extension",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0x00),PCI_CONF_PM_CAP_ID
+PCI_PMCSR_BSE
);
snprintf(reg_descr
,100,"%s LSISAS1064E Power Mgmt Data",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0x00),PCI_CONF_PM_CAP_ID
+PCI_PMDATA
);
addMsiCap(0x0,PCI_CONF_MSI_CAP_ID
,0x0080);
snprintf(reg_descr
,100,"%s LSISAS1064E MSI Reserved",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,1,0x00,0x00),PCI_CONF_MSI_CAP_ID
+0xe);
snprintf(reg_descr
,100,"%s LSISAS1064E MSI Mask Bits",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,4,0x00000000,0xffffffff),PCI_CONF_MSI_CAP_ID
+0x10);
snprintf(reg_descr
,100,"%s LSISAS1064E MSI Pending Bits",getName());
confSpace
->addConfReg(new pciConfReg(reg_descr
,4,0x00000000,0x00000000),PCI_CONF_MSI_CAP_ID
+0x14);
void SAS::handle_ui_cmd(int argc
, char * argv
[]) {
printf("%s supports following UI commands\n",getName());
printf("%s debug [<level>]\n\
set the debug level for debug prints to \'level\'\n\
if \'level\' not provided, print current debug level\n\
\'level\' = [0|1|2]\n", getName());
show all attached disks\n", getName());
} else if (!strcmp(argv
[1], "debug")) {
int level
= atoi(argv
[2]);
if (level
!= 0 && level
!= 1 && level
!= 2)
debug_err("%s: unsupported debug level <%s>\n", getName(), argv
[2]);
confSpace
->set_debug_level(debug_level
);
printf("%s: set debug level to %d\n", getName(), debug_level
);
printf("%s: current debug level %d\n", getName(), debug_level
);
} else if (!strcmp(argv
[1], "disk")) {
printf("attached disks:\n");
for (int i
= 0; i
< IOC_NUM_PORTS
; i
++)
printf("%s is attached to target %d\n", _disk
[i
]->get_name(), i
);
debug_err("%s: unsupported UI command <%s>\n", getName(), argv
[1]);
int sas_ui_cmd(void *obj
, int argc
, char * argv
[]){
SAS
*sas
= dynamic_cast<SAS
*>((Module
*)obj
);
sas
->handle_ui_cmd(argc
, argv
);
if (!isDir(overlaydir
)) {
int status
= mkdir(overlaydir
, 0777);
debug_err("%s: Unable to create disk overlay dir: %s (%s)\n", getName(), overlaydir
, strerror(errno
));
// .nsr is created in overlay directory to avoid backup of shadow files
char *fname
= (char *)malloc(strlen(overlaydir
) + 6);
sprintf(fname
, "%s/.nsr", overlaydir
);
FILE *fp
= fopen(fname
, "w");
debug_err("%s: Unable to creat .nsr in %s (%s)\n", getName(), overlaydir
, strerror(errno
));
fprintf(fp
, "+null: * .?*\n");
status
= atexit(overlaydir_cleanup
);
debug_err("%s: Unable to register cleanup function for overlay dir: %s (%s)\n", getName(), overlaydir
, strerror(errno
));
for (int i
= 0; i
< IOC_NUM_PORTS
; i
++)
// open disk configuration file, try the restore directory first
char *restore_dir
= get_restore_dir();
// need to extract file name
for (i
= strlen(fname
) - 1; i
>= 0; i
--)
char *name
= strdup(&fname
[i
+1]);
// open it if it is in the restore directory
char *dev_name
= (char *)getName();
char *rname
= (char *)malloc(strlen(restore_dir
) + strlen(dev_name
) + strlen(name
) + 15);
sprintf(rname
, "%s/sas_ctrl_%s/%s", restore_dir
, dev_name
, name
);
debug_info("%s: can't find sas disk configuration file: %s in the restore directory\n", getName(), name
);
// update fname with rname
if (strlen(fname
) < strlen(rname
)) {
strcpy((char *)fname
, rname
);
// open disk configuration file, try the one specified in .rc file next
debug_err("%s: can't find sas disk configuration file: %s\n", getName(), fname
);
for (int target_id
= 0; target_id
< IOC_NUM_PORTS
; target_id
++) {
SCSIDisk
*disk
= new SCSIDisk
;
// disk name is constructed as controller name + "t" + tatget_id
sprintf(disk_name
, "%st%d", getName(), target_id
);
disk
->set_name(disk_name
);
disk
->set_target(target_id
);
disk
->parse_config(fname
, fp
, target_id
);
if (disk
->get_num_partitions() == 0) {
debug_info("%s: disk %s is attached as target %d, total number of partitons: %d\n",
getName(), disk
->get_name(), disk
->get_target_id(), disk
->get_num_partitions());
mmi_register_instance_cmd(getInstance(), get_help(), sas_ui_cmd
);
// initialize pci registers
dev_init_done(Module::debug_level
);
void SAS::module_added(mmi_instance_t target
, const char *target_name
) {
dev_module_added(target_name
);
void SAS::module_deleted(mmi_instance_t target
, const char *target_name
) {
dev_module_deleted(target_name
);
printf("%s is a %s\n", getName(), SAS1064E_Help
);
printf(" Vendor id <0x%lx>, Device id <0x%lx>\n", confSpace
->readConf(PCI_CONF_VENID
), confSpace
->readConf(PCI_CONF_DEVID
));
printf(" Upstream pcie bus is <%s>\n", busName
);
printf(" Disk configuration file is <%s>\n", fname
);
printf(" Type \'%s\' for the description of supported UI commands\n", getName());
void *SAS::get_interface(const char *name
) {
if (!strcmp(name
, GENERIC_PCIE_DEV_INTERFACE
))
return (genericPcieDevIf
*)this;
bzero(_mpt_reg
, sizeof(mpt_reg_t
));
// clear ioc configuration
bzero(_ioc_conf
, sizeof(ioc_conf_t
));
// clear earliest serving time
bzero(_earliest_serving_time
, sizeof(uint64_t) * IOC_NUM_PORTS
);
bzero(_port_enabled
, sizeof(uint8_t) * IOC_NUM_PORTS
);
// clear handshake messages
bzero(_hdshk_msg_req_buf
, HDSHK_MSG_SIZE
);
bzero(_hdshk_msg_reply_buf
, HDSHK_MSG_SIZE
);
_hdshk_msg_reply_size
= 0;
_hdshk_msg_reply_send
= 0;
while (!_reply_post_queue
.empty())
while (!_reply_free_queue
.empty())
// set ioc to ready state
_mpt_reg
->doorbell
= (_mpt_reg
->doorbell
& ~MPI_IOC_STATE_MASK
) |
_mpt_reg
->intr_mask
|= MPI_HIM_DIM
;
_mpt_reg
->intr_mask
|= MPI_HIM_RIM
;
pcieCompleter
SAS::devif_confAccess(bool wr
, uint32_t offset
, void * data
, \
uint8_t be
,uint16_t reqId
, addrMd_xactnType tType
, uint16_t length
, tlp_X args
,SAM_DeviceId
* id
) {
int size
= byteEnabletoSize(be
); // length is the number of words
*(uint64_t*)data
&= 0xFFFFFFFF;
uint32_t l_buf
= *(uint64_t*)data
;
*(uint64_t*)data
= swap_word(l_buf
);
*(uint64_t*)data
= swap_hword(l_buf
);
*(uint64_t*)data
= l_buf
;
debug_info("%s: conf xactn type 0: offset <0x%x> wr size<%d> be<0x%x> data<0x%llx>\n",
getName(), offset
, size
, be
,*(uint64_t*)data
);
ret
= confSpace
->confAccessSize(offset
, wr
, (uint64_t *)data
, size
);
if (wr
) debug_info("\n");
uint32_t l_buf
= *(uint64_t*)data
;
*(uint64_t*)data
= swap_word(l_buf
& 0xFFFFFFFF);
*(uint64_t*)data
= swap_hword(l_buf
& 0xFFFF);
*(uint64_t*)data
= l_buf
& 0xFF;
debug_info("%s: conf xactn type 0: offset <0x%x> rd size<%d> be<0x%x> data<0x%llx>\n",
getName(), offset
, size
, be
, *(uint64_t*)data
);
devif_confAccessCb(wr
,offset
,be
);
return (ret
? pcieCompleter(SC
,getId()) : pcieCompleter(CA
,getId()));
void SAS::devif_confAccessCb(bool wr
, uint64_t offset
, uint8_t be
) {
if(offset
== PCI_CONF_BASE0
){
_io_base
= confSpace
->readConf(offset
) & 0xfffffffc;
}else if (offset
== PCI_CONF_BASE1
|| offset
== PCI_CONF_BASE2
){
pcieBaseAddrReg
* r
= (pcieBaseAddrReg
*)confSpace
->getConfReg(PCI_CONF_BASE1
);
_mem0_base
= ((uint64_t)(r
->val_32To63
)) << 32 |(r
->getVal() & 0xfffffff0) ;
}else if (offset
== PCI_CONF_BASE3
|| offset
== PCI_CONF_BASE4
){
pcieBaseAddrReg
* r
= (pcieBaseAddrReg
*)confSpace
->getConfReg(PCI_CONF_BASE3
);
_mem1_base
= ((uint64_t)(r
->val_32To63
)) << 32 |(r
->getVal() & 0xfffffff0) ;
bool SAS::msi_enabled() {
uint16_t msi_msg_ctrl
= confSpace
->readConf(PCI_CONF_MSI_CAP_ID
+ MSI_MSGCNTRL_OFFSET
);
return(msi_msg_ctrl
& 0x1);
// called whenever IOC writes a value to doorbell
void SAS::set_doorbell_interrupt() {
bool pending
= _mpt_reg
->intr_status
& MPI_HIS_DOORBELL_INTERRUPT
;
// set doorbell interrupt bit
_mpt_reg
->intr_status
|= MPI_HIS_DOORBELL_INTERRUPT
;
// send interrupt if it is unmasked and no pending doorbell interrupt
if (!(_mpt_reg
->intr_mask
& MPI_HIM_DIM
) && !pending
) {
debug_info("%s: send doorbell MSI\n", getName());
uint32_t lo
= confSpace
->readConf(PCI_CONF_MSI_CAP_ID
+ MSI_MSGADDR0_OFFSET
);
uint32_t hi
= confSpace
->readConf(PCI_CONF_MSI_CAP_ID
+ MSI_MSGADDR1_OFFSET
);
uint64_t msi_addr
= ((uint64_t)hi
<< 32) | lo
;
uint32_t msi_data
= confSpace
->readConf(PCI_CONF_MSI_CAP_ID
+ MSI_MSGDATA64_OFFSET
);
pcieCompleter status
= busIf
->busif_access(PCIE_MEM
, true, msi_addr
, (void*)&msi_data
,
1, 0xf, getId(), mem_addr64
, &samId
);
if (handleCompletion(status
) == -1) {
debug_err("%s: pcie error when sending doorbell MSI\n");
debug_info("%s: send doorbell INTx\n", getName());
pcieCompleter status
= busIf
->busif_msgAccess((uint8_t)MSG_Assert_INTA
, local
, getId(),&samId
);
if (handleCompletion(status
) == -1) {
debug_err("%s: pcie error when sending doorbell INTx\n");
// called whenever IOC writes a reply msg descriptor to reply post queue
void SAS::set_reply_msg_interrupt() {
bool pending
= _mpt_reg
->intr_status
& MPI_HIS_REPLY_MESSAGE_INTERRUPT
;
// set reply msg interrupt bit
_mpt_reg
->intr_status
|= MPI_HIS_REPLY_MESSAGE_INTERRUPT
;
// send interrupt if it is unmasked and no pending reply msg interrupt
if (!(_mpt_reg
->intr_mask
& MPI_HIM_RIM
) && !pending
) {
debug_info("%s: send reply msg MSI\n", getName());
uint32_t lo
= confSpace
->readConf(PCI_CONF_MSI_CAP_ID
+ MSI_MSGADDR0_OFFSET
);
uint32_t hi
= confSpace
->readConf(PCI_CONF_MSI_CAP_ID
+ MSI_MSGADDR1_OFFSET
);
uint64_t msi_addr
= ((uint64_t)hi
<< 32) | lo
;
uint32_t msi_data
= confSpace
->readConf(PCI_CONF_MSI_CAP_ID
+ MSI_MSGDATA64_OFFSET
);
pcieCompleter status
= busIf
->busif_access(PCIE_MEM
, true, msi_addr
, (void*)&msi_data
,
1, 0xf, getId(), mem_addr64
, &samId
);
if (handleCompletion(status
) == -1) {
debug_err("%s: pcie error when sending reply msg MSI\n");
debug_info("%s: send reply msg INTx\n", getName());
pcieCompleter status
= busIf
->busif_msgAccess((uint8_t)MSG_Assert_INTA
, local
, getId(),&samId
);
if (handleCompletion(status
) == -1) {
debug_err("%s: pcie error when sending reply msg INTx\n");
void SAS::doorbell_function_handshake(uint8_t size
) {
// set by ioc to indicate it starts to perform a doorbell function
_mpt_reg
->doorbell
|= MPI_DOORBELL_USED
;
// clear to indicate ioc has read the message
_mpt_reg
->intr_status
&= ~MPI_HIS_IOP_DOORBELL_STATUS
;
// set the size of total and received handhake message (in dword)
bzero(_hdshk_msg_req_buf
, HDSHK_MSG_SIZE
);
assert(size
> 0 && size
<= HDSHK_MSG_SIZE
>> 2);
_hdshk_msg_req_size
= size
;
// set by ioc after the doorbell is written
set_doorbell_interrupt();
void SAS::doorbell_function_reply_frame_removal() {
// set by ioc to indicate it starts to perform a doorbell function
_mpt_reg
->doorbell
|= MPI_DOORBELL_USED
;
// clear to indicate ioc has read the message
_mpt_reg
->intr_status
&= ~MPI_HIS_IOP_DOORBELL_STATUS
;
// use doorbell to send the reply message
*((uint32_t *)_hdshk_msg_reply_buf
) = SAM_LE_32(_reply_free_queue
.size());
_hdshk_msg_reply_size
= 1;
while (!_reply_free_queue
.empty()) {
*((uint32_t *)_hdshk_msg_reply_buf
+ _hdshk_msg_reply_size
) = SAM_LE_32(_reply_free_queue
.front());
// set the size of message to be sent in hword
_hdshk_msg_reply_size
= _hdshk_msg_reply_size
<< 1;
_hdshk_msg_reply_send
= 0;
// put the first hword in the doorbell
value
= *(uint16_t *)(_hdshk_msg_reply_buf
+ (_hdshk_msg_reply_send
<< 1));
value
= SAM_LE_16(value
);
_mpt_reg
->doorbell
= (_mpt_reg
->doorbell
& ~MPI_DOORBELL_DATA_MASK
) | value
;
// set by ioc after the doorbell is written
set_doorbell_interrupt();
void SAS::doorbell_function_ioc_msg_unit_reset() {
// set by ioc to indicate it starts to perform a doorbell function
_mpt_reg
->doorbell
|= MPI_DOORBELL_USED
;
// clear to indicate ioc has read the message
_mpt_reg
->intr_status
&= ~MPI_HIS_IOP_DOORBELL_STATUS
;
while (!_reply_post_queue
.empty())
while (!_reply_free_queue
.empty())
// set ioc to ready state
_mpt_reg
->doorbell
= (_mpt_reg
->doorbell
& ~MPI_IOC_STATE_MASK
) |
// clear to indicate ioc finishes doorbell function
_mpt_reg
->doorbell
&= ~MPI_DOORBELL_USED
;
void SAS::access_door_bell(bool wr
, uint64_t *in_buf
, uint8_t size
) {
uint32_t value
= *in_buf
;
// request messages received through doorbell handshake
// message is written in 4 bytes chunk using little endian model
if (_hdshk_msg_req_recv
< _hdshk_msg_req_size
) {
*((uint32_t *)(_hdshk_msg_req_buf
+ (_hdshk_msg_req_recv
<< 2))) = SAM_LE_32(value
);
_mpt_reg
->intr_status
&= ~MPI_HIS_IOP_DOORBELL_STATUS
;
if (_hdshk_msg_req_recv
== _hdshk_msg_req_size
) {
uint32_t d_fun
= (value
& MPI_DOORBELL_FUNCTION_MASK
) >> MPI_DOORBELL_FUNCTION_SHIFT
;
case MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET
:
doorbell_function_ioc_msg_unit_reset();
case MPI_FUNCTION_IO_UNIT_RESET
:
debug_err("%s: MPI_FUNCTION_IO_UNIT_RESET no impl\n", getName());
case MPI_FUNCTION_HANDSHAKE
:
doorbell_function_handshake((value
& MPI_DOORBELL_ADD_DWORDS_MASK
) >>
MPI_DOORBELL_ADD_DWORDS_SHIFT
);
case MPI_FUNCTION_REPLY_FRAME_REMOVAL
:
doorbell_function_reply_frame_removal();
case MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
:
debug_err("%s: MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL no impl\n", getName());
debug_err("%s: unknown doorbell function\n", getName());
*in_buf
= _mpt_reg
->doorbell
;
void SAS::access_write_sequence(bool wr
, uint64_t *in_buf
, uint8_t size
) {
uint32_t key_value
= *in_buf
& MPI_WRSEQ_KEY_VALUE_MASK
;
debug_err("%s: write sequence register is write only!\n", getName());
// A sequence of values have to be written before Host Diagnostic register is accessed.
// Any incorrect value will cause the restart of matching process.
case MPI_WRSEQ_1ST_KEY_VALUE
:
// disable host diag write if it is set
if (_mpt_reg
->write_seq
== MPI_WRSEQ_5TH_KEY_VALUE
)
_mpt_reg
->diag
&= ~MPI_DIAG_DRWE
;
_mpt_reg
->write_seq
= key_value
;
case MPI_WRSEQ_2ND_KEY_VALUE
:
// disable host diag write if it is set
if (_mpt_reg
->write_seq
== MPI_WRSEQ_5TH_KEY_VALUE
)
_mpt_reg
->diag
&= ~MPI_DIAG_DRWE
;
if (_mpt_reg
->write_seq
== MPI_WRSEQ_1ST_KEY_VALUE
)
_mpt_reg
->write_seq
= key_value
;
case MPI_WRSEQ_3RD_KEY_VALUE
:
// disable host diag write if it is set
if (_mpt_reg
->write_seq
== MPI_WRSEQ_5TH_KEY_VALUE
)
_mpt_reg
->diag
&= ~MPI_DIAG_DRWE
;
if (_mpt_reg
->write_seq
== MPI_WRSEQ_2ND_KEY_VALUE
)
_mpt_reg
->write_seq
= key_value
;
case MPI_WRSEQ_4TH_KEY_VALUE
:
// disable host diag write if it is set
if (_mpt_reg
->write_seq
== MPI_WRSEQ_5TH_KEY_VALUE
)
_mpt_reg
->diag
&= ~MPI_DIAG_DRWE
;
if (_mpt_reg
->write_seq
== MPI_WRSEQ_3RD_KEY_VALUE
)
_mpt_reg
->write_seq
= key_value
;
case MPI_WRSEQ_5TH_KEY_VALUE
:
// disable host diag write if it is set
if (_mpt_reg
->write_seq
== MPI_WRSEQ_5TH_KEY_VALUE
)
_mpt_reg
->diag
&= ~MPI_DIAG_DRWE
;
if (_mpt_reg
->write_seq
== MPI_WRSEQ_4TH_KEY_VALUE
)
_mpt_reg
->write_seq
= key_value
;
// enable host diag write
if (_mpt_reg
->write_seq
== MPI_WRSEQ_5TH_KEY_VALUE
)
_mpt_reg
->diag
|= MPI_DIAG_DRWE
;
_mpt_reg
->diag
&= ~MPI_DIAG_DRWE
;
void SAS::access_host_diagnostic(bool wr
, uint64_t *in_buf
, uint8_t size
) {
uint32_t value
= *in_buf
& 0x7ff;
if (value
& MPI_DIAG_RESET_ADAPTER
) {
_mpt_reg
->diag
&= ~MPI_DIAG_RESET_ADAPTER
;
*in_buf
= _mpt_reg
->diag
;
void SAS::access_test_base_address(bool wr
, uint64_t *in_buf
, uint8_t size
) {
_mpt_reg
->test_base_addr
= *in_buf
;
*in_buf
= _mpt_reg
->test_base_addr
;
void SAS::access_diag_rw_data(bool wr
, uint64_t *in_buf
, uint8_t size
) {
_mpt_reg
->diagrw_data
= *in_buf
;
*in_buf
= _mpt_reg
->diagrw_data
;
void SAS::access_diag_rw_address(bool wr
, uint64_t *in_buf
, uint8_t size
) {
_mpt_reg
->diagrw_addr
= *in_buf
;
*in_buf
= _mpt_reg
->diagrw_addr
;
void SAS::access_host_interrupt_status(bool wr
, uint64_t *in_buf
, uint8_t size
) {
uint32_t l_buf
= *in_buf
;
if (_mpt_reg
->intr_status
& MPI_HIS_DOORBELL_INTERRUPT
) {
// don't deassert interrupt if reply msg interrupt is set
if ((_mpt_reg
->intr_status
& MPI_HIS_REPLY_MESSAGE_INTERRUPT
) == 0) {
debug_info("%s: deassert interrupt\n", getName());
pcieCompleter status
= busIf
->busif_msgAccess((uint8_t)MSG_Deassert_INTA
, local
, getId(),&samId
);
if (handleCompletion(status
) == -1) {
debug_err("%s: pcie error when deasserting doorbell interrupt\n");
// reply msg interrupt is not cleared by ANY write
_mpt_reg
->intr_status
= l_buf
| (_mpt_reg
->intr_status
& MPI_HIS_REPLY_MESSAGE_INTERRUPT
);
// doorbell interrupt is always cleared by ANY write
_mpt_reg
->intr_status
&= ~MPI_HIS_DOORBELL_INTERRUPT
;
// reply messages sent through doorbell handshake
if ((_mpt_reg
->intr_status
& MPI_HIS_DOORBELL_INTERRUPT
) == 0) {
if (_hdshk_msg_reply_send
< _hdshk_msg_reply_size
) {
uint32_t value
= SAM_LE_16(*(uint16_t *)(_hdshk_msg_reply_buf
+ (_hdshk_msg_reply_send
<< 1)));
_mpt_reg
->doorbell
= (_mpt_reg
->doorbell
& ~MPI_DOORBELL_DATA_MASK
) | value
;
// set by ioc after the doorbell is written
set_doorbell_interrupt();
else if (_hdshk_msg_reply_send
> 0 && _hdshk_msg_reply_send
== _hdshk_msg_reply_size
) {
_hdshk_msg_reply_size
= 0;
_hdshk_msg_reply_send
= 0;
// clear to indicate ioc finishes doorbell function
_mpt_reg
->doorbell
&= ~MPI_DOORBELL_USED
;
// set by ioc after the doorbell is written
set_doorbell_interrupt();
*in_buf
= _mpt_reg
->intr_status
;
void SAS::access_host_interrupt_mask(bool wr
, uint64_t *in_buf
, uint8_t size
) {
// In some very rare cases, target probe starts (which masks the interrupt)
// while ioc is still processing a scsi cmd. We avoid mask in such cases.
bool pending_cmd
= false;
for (int i
= 0; i
< EVENT_TABLE_SIZE
; i
++) {
if (_etable
.events
[i
].used
) {
debug_info("%s: ioc is busy, reply msg interrupt will not be masked \n", getName());
_mpt_reg
->intr_mask
= (_mpt_reg
->intr_mask
& MPI_HIM_RIM
) | (*in_buf
& ~MPI_HIM_RIM
);
_mpt_reg
->intr_mask
= *in_buf
;
*in_buf
= _mpt_reg
->intr_mask
;
void SAS::access_host_request_queue(bool wr
, uint64_t *in_buf
, uint8_t size
) {
uint32_t l_buf
= *in_buf
;
// request is processed immediately after it is received,
// so request post queue is not needed.
// timing model is done through event table
int entry
= _etable
.alloc();
process_mpi_msg(entry
, l_buf
);
int64_t invoke_time
= _etable
.get_invoke_time(entry
);
int64_t current_time
= mmi_get_time();
debug_info("%s: io request is received, current time is %lld\n", getName(), current_time
);
if (invoke_time
== current_time
) {
// no disk delay is simulated, finish it immediately
sas_io_callback((void *)this, (void*)entry
);
} else if (invoke_time
> current_time
) {
// register callback function since we now know when an io request will finish
mmi_register_event(_etable
.get_invoke_time(entry
), (EventFunc_T
*)&sas_io_callback
, (void *)this, (void *)entry
);
// invoke time should not be less than current time
debug_err("%s: callback function invoke time %lld is less than current time %lld\n", getName(), invoke_time
, current_time
);
*in_buf
= _mpt_reg
->req_q
;
void SAS::access_reply_queue(bool wr
, uint64_t *in_buf
, uint8_t size
) {
uint32_t l_buf
= *in_buf
;
// each written value is regarded as reply free MFA from the host
// which will be pushed into reply free queue
_reply_free_queue
.push(l_buf
);
// without disk delay, reading reply queue and updating reply
// queue are mutually exclusive (protected by lock in mpt driver).
// if disk delay is simulated, this is no longer true, because
// updating reply queue is done some time later after a request
// is received, and it is no longer under the proctection of mpt driver.
pthread_mutex_lock(&_reply_queue_mutex
);
if (!_reply_post_queue
.empty()) {
assert(_mpt_reg
->intr_status
& MPI_HIS_REPLY_MESSAGE_INTERRUPT
);
_mpt_reg
->reply_q
= _reply_post_queue
.front();
if (_reply_post_queue
.empty()) {
// self-clear reply message interrupt if queue is empty
_mpt_reg
->intr_status
&= ~MPI_HIS_REPLY_MESSAGE_INTERRUPT
;
// don't deassert interrupt if doorbell interrupt is set
if ((_mpt_reg
->intr_status
& MPI_HIS_DOORBELL_INTERRUPT
) == 0) {
debug_info("%s: deassert interrupt\n", getName());
pcieCompleter status
= busIf
->busif_msgAccess((uint8_t)MSG_Deassert_INTA
, local
, getId(),&samId
);
if (handleCompletion(status
) == -1) {
debug_err("%s: pcie error when deasserting reply msg interrupt\n");
// interrupt should have been cleared when the last message is read
assert(!(_mpt_reg
->intr_status
& MPI_HIS_REPLY_MESSAGE_INTERRUPT
));
// send 0xffffffff to the host indicating reply post queue is empty
_mpt_reg
->reply_q
= 0xffffffff;
_mpt_reg
->intr_status
&= ~MPI_HIS_REPLY_MESSAGE_INTERRUPT
;
pthread_mutex_unlock(&_reply_queue_mutex
);
*in_buf
= _mpt_reg
->reply_q
;
void SAS::access_hi_pri_request_queue(bool wr
, uint64_t *in_buf
, uint8_t size
) {
_mpt_reg
->pri_req_q
= *in_buf
;
*in_buf
= _mpt_reg
->pri_req_q
;
bool SAS::memory_space_access(int offset
,bool wr
, uint64_t *in_buf
, uint8_t size
) {
if (offset
>= _io_base
&& offset
< _io_base
+ IO_SIZE
) {
else if (offset
>= _mem0_base
&& offset
< _mem0_base
+ MEM0_SIZE
) {
else if (offset
>= _mem1_base
&& offset
< _mem1_base
+ MEM1_SIZE
) {
debug_err("%s: memory space 0x%llx is not allocated\n", getName(), offset
);
case MPI_DOORBELL_OFFSET
:
access_door_bell(wr
, in_buf
, size
);
case MPI_WRITE_SEQUENCE_OFFSET
:
access_write_sequence(wr
, in_buf
, size
);
case MPI_DIAGNOSTIC_OFFSET
:
access_host_diagnostic(wr
, in_buf
, size
);
case MPI_TEST_BASE_ADDRESS_OFFSET
:
access_test_base_address(wr
, in_buf
, size
);
case MPI_DIAG_RW_DATA_OFFSET
:
access_diag_rw_data(wr
, in_buf
, size
);
case MPI_DIAG_RW_ADDRESS_OFFSET
:
access_diag_rw_address(wr
, in_buf
, size
);
case MPI_HOST_INTERRUPT_STATUS_OFFSET
:
access_host_interrupt_status(wr
, in_buf
, size
);
case MPI_HOST_INTERRUPT_MASK_OFFSET
:
access_host_interrupt_mask(wr
, in_buf
, size
);
case MPI_REQUEST_QUEUE_OFFSET
:
access_host_request_queue(wr
, in_buf
, size
);
case MPI_REPLY_QUEUE_OFFSET
:
access_reply_queue(wr
, in_buf
, size
);
case MPI_HI_PRI_REQUEST_QUEUE_OFFSET
:
access_hi_pri_request_queue(wr
, in_buf
, size
);
debug_err("%s: memory space 0x%llx is reserved\n", getName(), offset
);
pcieCompleter
SAS::devif_memAccess(bool wr
, uint64_t offset
, addrMd_xactnType mode
, void * data
,\
uint16_t length
, uint8_t be
, uint16_t reqId
, tlp_X args
,SAM_DeviceId
*id
) {
int size
= byteEnabletoSize(be
);
*(uint64_t*)data
&= 0xFFFFFFFF;
uint32_t l_buf
= *(uint64_t*)data
;
*(uint64_t*)data
= swap_word(l_buf
);
*(uint64_t*)data
= swap_hword(l_buf
);
*(uint64_t*)data
= l_buf
;
debug_info("%s: memory space: offset <0x%x> wr size<%d> be<0x%x> data<0x%llx>\n",
getName(), offset
, size
, be
, *(uint64_t*)data
);
ret
= memory_space_access(offset
, wr
, (uint64_t *)data
, size
);
uint32_t l_buf
= *(uint64_t*)data
;
*(uint64_t*)data
= swap_word(l_buf
& 0xFFFFFFFF);
*(uint64_t*)data
= swap_hword(l_buf
& 0xFFFF);
*(uint64_t*)data
= l_buf
& 0xFF;
debug_info("%s: memory space: offset <0x%x> rd size<%d> be<0x%x> data<0x%llx>\n",
getName(), offset
, size
, be
, *(uint64_t*)data
);
return (ret
? pcieCompleter(SC
,getId()) : pcieCompleter(UR
,getId()));
pcieCompleter
SAS::devif_ioAccess(bool wr
, uint32_t offset
, void * data
, uint8_t be
, \
uint16_t reqId
, uint16_t length
, tlp_X args
,SAM_DeviceId
* id
) {
debug_info("%s: io space 0x%llx is %s\n", getName(), offset
, wr
?"written":"read");
pcieCompleter
SAS::devif_msgAccess(uint8_t messageCode
, msgRouting route
, uint64_t tarIdOrAddr
, uint16_t reqId
, \
void * data
, uint16_t length
, uint16_t vendorId
, uint32_t vendor_data
, tlp_X args
,SAM_DeviceId
* id
) {
debug_info("%s: message space is accessed\n", getName());
const char *Module::get_help_string(){
Module
*Module::create(const char *_modname
, const char *_instance_name
){
return new SAS(_modname
, _instance_name
);
bool SAS::dump(FILE *fp
) {
const char *dump_dir
= DR_get_dir();
const char *dev_name
= getName();
// dump generic pcie device info into "dump_dir/dev_name.pcie"
bool ret
= genericPcieDev::dump(dump_dir
, dev_name
);
// dump all disk info are dumped into "dump_dir/sas_ctrl_dev_name/"
char *dirname
= (char *)malloc(strlen(dump_dir
) + strlen(dev_name
) + 15);
sprintf(dirname
, "%s/sas_ctrl_%s", dump_dir
, dev_name
);
if (mkdir(dirname
, S_IRWXU
| S_IRWXG
| S_IRWXO
) == -1) {
debug_err("%s: can't create directory %s\n", getName(), dirname
);
for (i
= 0; i
< IOC_NUM_PORTS
; i
++)
// dump all controller info into "dump_dir/dev_name.dmp"
// there are several categories, each categories starts with "#category_name number_of_fields"
fprintf(fp
, "#reg %d\n", 11);
fprintf(fp
, "reg_doorbell %u\n", _mpt_reg
->doorbell
);
fprintf(fp
, "reg_write_seq %u\n", _mpt_reg
->write_seq
);
fprintf(fp
, "reg_diag %u\n", _mpt_reg
->diag
);
fprintf(fp
, "reg_test_base_addr %u\n", _mpt_reg
->test_base_addr
);
fprintf(fp
, "reg_diagrw_data %u\n", _mpt_reg
->diagrw_data
);
fprintf(fp
, "reg_diagrw_addr %u\n", _mpt_reg
->diagrw_addr
);
fprintf(fp
, "reg_intr_status %u\n", _mpt_reg
->intr_status
);
fprintf(fp
, "reg_intr_mask %u\n", _mpt_reg
->intr_mask
);
fprintf(fp
, "reg_req_q %u\n", _mpt_reg
->req_q
);
fprintf(fp
, "reg_reply_q %u\n", _mpt_reg
->reply_q
);
fprintf(fp
, "reg_pri_req_q %u\n", _mpt_reg
->pri_req_q
);
// dump ioc configuration
fprintf(fp
, "#conf %d\n", 9);
fprintf(fp
, "conf_who_init %hhu\n", _ioc_conf
->who_init
);
fprintf(fp
, "conf_max_devices %hhu\n", _ioc_conf
->max_devices
);
fprintf(fp
, "conf_max_buses %hhu\n", _ioc_conf
->max_buses
);
fprintf(fp
, "conf_reply_frame_size %hu\n", _ioc_conf
->reply_frame_size
);
fprintf(fp
, "conf_host_mfa_high_addr %u\n", _ioc_conf
->host_mfa_high_addr
);
fprintf(fp
, "conf_sense_buffer_high_addr %u\n", _ioc_conf
->sense_buffer_high_addr
);
fprintf(fp
, "conf_host_page_buffer_sge_FlagsLength %u\n", _ioc_conf
->host_page_buffer_sge
.FlagsLength
);
fprintf(fp
, "conf_host_page_buffer_sge_Address_Low %u\n", _ioc_conf
->host_page_buffer_sge
.Address_Low
);
fprintf(fp
, "conf_host_page_buffer_sge_Address_High %u\n", _ioc_conf
->host_page_buffer_sge
.Address_High
);
// dump eariliest serving time
fprintf(fp
, "#port_est %d\n", IOC_NUM_PORTS
);
for (i
= 0; i
< IOC_NUM_PORTS
; i
++)
fprintf(fp
, "port[%d] %lld\n", i
, _earliest_serving_time
[i
]);
fprintf(fp
, "#port_enabled %d\n", IOC_NUM_PORTS
);
for (i
= 0; i
< IOC_NUM_PORTS
; i
++)
fprintf(fp
, "port[%d] %hhu\n", i
, _port_enabled
[i
]);
// dump handshake request messages
fprintf(fp
, "#hdshk_msg_req %d\n", _hdshk_msg_req_size
+2);
fprintf(fp
, "hdshk_msg_req_size %hhu\n", _hdshk_msg_req_size
);
fprintf(fp
, "hdshk_msg_req_recv %hhu\n", _hdshk_msg_req_recv
);
for (i
= 0; i
< (_hdshk_msg_req_size
<< 2); i
++)
fprintf(fp
, "hdshk_msg_req_buf[%d], %hhu\n", i
, _hdshk_msg_req_buf
[i
]);
// dump handshake reply messages
fprintf(fp
, "#hdshk_msg_reply %d\n", _hdshk_msg_reply_size
+2);
fprintf(fp
, "hdshk_msg_reply_size %hhu\n", _hdshk_msg_reply_size
);
fprintf(fp
, "hdshk_msg_reply_send %hhu\n", _hdshk_msg_reply_send
);
for (i
= 0; i
< (_hdshk_msg_reply_size
<< 2); i
++)
fprintf(fp
, "hdshk_msg_reply_buf[%d], %hhu\n", i
, _hdshk_msg_reply_buf
[i
]);
fprintf(fp
, "#request_queue %d\n", _request_queue_size
);
qsize
= _reply_post_queue
.size();
fprintf(fp
, "#reply_post_queue %d\n", qsize
);
for (i
= 0; i
< qsize
; i
++) {
qvalue
= _reply_post_queue
.front();
fprintf(fp
, "reply_post_queue[%d] %u\n", i
, qvalue
);
_reply_post_queue
.push(qvalue
);
qsize
= _reply_free_queue
.size();
fprintf(fp
, "#reply_free_queue %d\n", qsize
);
for (i
= 0; i
< qsize
; i
++) {
qvalue
= _reply_free_queue
.front();
fprintf(fp
, "reply_free_queue[%d] %u\n", i
, qvalue
);
_reply_free_queue
.push(qvalue
);
fprintf(fp
, "#event_table %d\n", EVENT_TABLE_SIZE
);
// copy disk configuration file into "dump_dir/sas_ctrl_dev_name/"
char *cpcmd
= (char *)malloc(strlen(fname
) + strlen(dirname
) + 10);
sprintf(cpcmd
, "cp %s %s", fname
, dirname
);
if (system(cpcmd
) != 0) {
debug_err("%s: can't dump disk configuration file %s to %s\n", getName(), fname
, dirname
);
bool SAS::restore(FILE * fp
) {
const char *dump_dir
= DR_get_dir();
const char *dev_name
= getName();
char name
[128], type
[128];
// restore generic pcie device information from "dump_dir/dev_name.pcie"
bool ret
= genericPcieDev::restore(dump_dir
, dev_name
);
// restore disks from "dump_dir/sas_ctrl_dev_name/"
char *dirname
= (char *)malloc(strlen(dump_dir
) + strlen(dev_name
) + 15);
sprintf(dirname
, "%s/sas_ctrl_%s", dump_dir
, dev_name
);
for (i
= 0; i
< IOC_NUM_PORTS
; i
++)
_disk
[i
]->restore(dirname
);
// restore controller info from "dump_dir/dev_name.dmp".
// Data structure may be changed, so does checkpoint.
// We want to have compatibility among checkpoints,
// so a fully associative search/comparison is needed
// during restore. To make it efficient, info are organized
// into categories, so that we can afford fully associative
// search within each category, while each category itself
// is identified also by fully associative search.
// Some category may not need any search during restore.
while (fscanf(fp
, "%s %d\n", &type
, &items
) != EOF
) {
if (strcmp(type
, "#reg") == NULL
) {
for (i
= 0; i
< items
; i
++) {
fscanf(fp
, "%s %u\n", name
, ®_value
);
if (strcmp(name
, "reg_doorbell") == NULL
)
_mpt_reg
->doorbell
= reg_value
;
else if (strcmp(name
, "reg_write_seq") == NULL
)
_mpt_reg
->write_seq
= reg_value
;
else if (strcmp(name
, "reg_diag") == NULL
)
_mpt_reg
->diag
= reg_value
;
else if (strcmp(name
, "reg_test_base_addr") == NULL
)
_mpt_reg
->test_base_addr
= reg_value
;
else if (strcmp(name
, "reg_diagrw_data") == NULL
)
_mpt_reg
->diagrw_data
= reg_value
;
else if (strcmp(name
, "reg_diagrw_addr") == NULL
)
_mpt_reg
->diagrw_addr
= reg_value
;
else if (strcmp(name
, "reg_intr_status") == NULL
)
_mpt_reg
->intr_status
= reg_value
;
else if (strcmp(name
, "reg_intr_mask") == NULL
)
_mpt_reg
->intr_mask
= reg_value
;
else if (strcmp(name
, "reg_req_q") == NULL
)
_mpt_reg
->req_q
= reg_value
;
else if (strcmp(name
, "reg_reply_q") == NULL
)
_mpt_reg
->reply_q
= reg_value
;
else if (strcmp(name
, "reg_pri_req_q") == NULL
)
_mpt_reg
->pri_req_q
= reg_value
;
debug_info("%s: unknown register %s\n", getName(), name
);
else if (strcmp(type
, "#conf") == NULL
) {
// restore ioc configuration
for (i
= 0; i
< items
; i
++) {
fscanf(fp
, "%s %u\n", name
, &conf_value
);
if (strcmp(name
, "conf_who_init") == NULL
)
_ioc_conf
->who_init
= conf_value
;
else if (strcmp(name
, "conf_max_devices") == NULL
)
_ioc_conf
->max_devices
= conf_value
;
else if (strcmp(name
, "conf_max_buses") == NULL
)
_ioc_conf
->max_buses
= conf_value
;
else if (strcmp(name
, "conf_reply_frame_size") == NULL
)
_ioc_conf
->reply_frame_size
= conf_value
;
else if (strcmp(name
, "conf_host_mfa_high_addr") == NULL
)
_ioc_conf
->host_mfa_high_addr
= conf_value
;
else if (strcmp(name
, "conf_sense_buffer_high_addr") == NULL
)
_ioc_conf
->sense_buffer_high_addr
= conf_value
;
else if (strcmp(name
, "conf_host_page_buffer_sge_FlagsLength") == NULL
)
_ioc_conf
->host_page_buffer_sge
.FlagsLength
= conf_value
;
else if (strcmp(name
, "conf_host_page_buffer_sge_Address_Low") == NULL
)
_ioc_conf
->host_page_buffer_sge
.Address_Low
= conf_value
;
else if (strcmp(name
, "conf_host_page_buffer_sge_Address_High") == NULL
)
_ioc_conf
->host_page_buffer_sge
.Address_High
= conf_value
;
else if (strcmp(type
, "#port_est") == NULL
) {
// restore eariliest serving time
for (i
= 0; i
< items
; i
++)
fscanf(fp
, "%s %lld\n", name
, &_earliest_serving_time
[i
]);
else if (strcmp(type
, "#port_enabled") == NULL
) {
for (i
= 0; i
< items
; i
++)
fscanf(fp
, "%s %hhu\n", name
, &_port_enabled
[i
]);
else if (strcmp(type
, "#hdshk_msg_req") == NULL
) {
// restore handshake request messages
fscanf(fp
, "%s %hhu\n", name
, &_hdshk_msg_req_size
);
fscanf(fp
, "%s %hhu\n", name
, &_hdshk_msg_req_recv
);
for (i
= 0; i
< (_hdshk_msg_req_size
<< 2); i
++)
fscanf(fp
, "%s %hhu\n", name
, &_hdshk_msg_req_buf
[i
]);
else if (strcmp(type
, "#hdshk_msg_reply") == NULL
) {
// restore handshake reply messages
fscanf(fp
, "%s %hhu\n", name
, &_hdshk_msg_reply_size
);
fscanf(fp
, "%s %hhu\n", name
, &_hdshk_msg_reply_send
);
for (i
= 0; i
< (_hdshk_msg_reply_size
<< 2); i
++)
fscanf(fp
, "%s %hhu\n", name
, &_hdshk_msg_reply_buf
[i
]);
else if (strcmp(type
, "#request_queue") == NULL
) {
_request_queue_size
= items
;
else if (strcmp(type
, "#reply_post_queue") == NULL
) {
// restore reply post queue
for (i
= 0; i
< items
; i
++) {
fscanf(fp
, "%s %u\n", name
, &qvalue
);
_reply_post_queue
.push(qvalue
);
else if (strcmp(type
, "#reply_free_queue") == NULL
) {
// restore reply free queue
for (i
= 0; i
< items
; i
++) {
fscanf(fp
, "%s %u\n", name
, &qvalue
);
_reply_free_queue
.push(qvalue
);
else if (strcmp(type
, "#event_table") == NULL
) {
_etable
.restore(this, fp
);
debug_info("%s: unknown type %s\n", getName(), type
);