* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: sas.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 ============================================
#define IOC_REPLY_QUEUE_DEPTH 128
#define IOC_REQ_QUEUE_DEPTH 128
#define IOC_PRI_QUEUE_DEPTH 128
#define IOC_REQ_FRAME_SIZE 128
#define IOC_CHAIN_DEPTH 128
#define IOC_BLOCK_SIZE 32
#define IOC_PRODUCTION_ID 101
#define IOC_CAPABILITIES 0xfc1
#define PORT_MAX_DEVICES 1
#define PORT_PROTOCOL_FLAGS 0xc
#define PORT_MAX_POSTED_CMD_BUFFERS 32
#define PORT_MAX_PERSISTENT_IDS 1
#define PORT_MAX_LAN_BUCKETS 0
// message frame address mask
#define FMA_ADDRESS_MASK 0xfffffff8
// maximal size of message (in byte) received/sent through doorbell handshake
#define HDSHK_MSG_SIZE 256
#define swap_hword(value) \
((uint32_t)(((value) & 0xff) << 8 | (value) >> 8))
#define swap_word(value) \
((uint32_t)((Word)swap_hword((HWord)((value) & 0xffff)) << 16 | \
(Word)swap_hword((HWord)((value) >> 16))))
#define swap_lword(value) \
((uint64_t)((((LWord)swap_word(LO_W(value))) << 32) | \
((LWord)swap_word(HI_W(value)))))
// system interface register set
uint16_t reply_frame_size
;
uint32_t host_mfa_high_addr
;
uint32_t sense_buffer_high_addr
;
sge_simple64_t host_page_buffer_sge
;
// event queue callback function
extern void sas_io_callback(void *arg1
, void *arg2
);
/* event table is used to support diskdelay.
It is not a FIFO, because some later request may
finish early than an early one.
allocate an entry: when a request is received.
free an entry: when a reply is read.
#define EVENT_TABLE_SIZE 128
// for diskdelay, parameters used to by send_mpi_rely() in the callback function
// callback function invoke time
event_table_entry_t events
[EVENT_TABLE_SIZE
];
int next
; // next available entry
for (int i
= 0; i
< EVENT_TABLE_SIZE
; i
++) {
events
[i
].invoke_time
= 0;
for (int i
= 0; i
< EVENT_TABLE_SIZE
; i
++) {
if (events
[entry
].used
== 0) {
events
[entry
].is_cntx
= 0;
events
[entry
].cntx_type
= 0;
events
[entry
].invoke_time
= 0;
if (next
== EVENT_TABLE_SIZE
)
if (entry
== EVENT_TABLE_SIZE
)
fprintf(stderr
, "no free entry in the event table\n");
void set_invoke_time(int entry
, int64_t time
) {
events
[entry
].invoke_time
= time
;
int64_t get_invoke_time(int entry
) {
return(events
[entry
].invoke_time
);
void done(int entry
, uint32_t reply
, uint8_t is_cntx
, uint8_t cntx_type
) {
events
[entry
].reply
= reply
;
events
[entry
].is_cntx
= is_cntx
;
events
[entry
].cntx_type
= cntx_type
;
void dump(SAS
*sasp
, FILE *fp
) {
fprintf(fp
, "next_entry %d\n", next
);
for (int i
= 0; i
< EVENT_TABLE_SIZE
; i
++) {
fprintf(fp
, "event_table[%d] %hhu %u %hhu %hhu %lld %hhu\n", i
,
void restore(SAS
*sasp
, FILE *fp
) {
fscanf(fp
, "%s %d\n", name
, &next
);
for (int i
= 0; i
< EVENT_TABLE_SIZE
; i
++) {
fscanf(fp
, "%s %hhu %u %hhu %hhu %lld %hhu\n", name
,
if (events
[i
].used
== 1) {
if (events
[i
].done
!= 1) {
printf("io request for event %d has not been processed yet\n", i
);
mmi_register_event(events
[i
].invoke_time
, (EventFunc_T
*)&sas_io_callback
, (void *)sasp
, (void *)i
);
class SAS
: public genericPcieDev
, public Module
{
const char *fname
; // configuration file
uint32_t _io_base
; // io base
uint64_t _mem0_base
; // mem0 base
uint64_t _mem1_base
; // mem1 base
uint8_t _hdshk_msg_req_size
; // the size of request msg received through doorbell handshake
uint8_t _hdshk_msg_req_recv
; // number of bytes received
uchar_t
*_hdshk_msg_req_buf
; // buffer for doorbell handshake request msg
uint8_t _hdshk_msg_reply_size
; // the size of reply msg sent through doorbell handshake
uint8_t _hdshk_msg_reply_send
; // number of bytes sent
uchar_t
*_hdshk_msg_reply_buf
; // buffer for doorbell handshake reply msg
mpt_reg_t
*_mpt_reg
; // system interface register set
ioc_conf_t
*_ioc_conf
; // ioc configuration
uint8_t *_port_enabled
; // port enabled
int64_t *_earliest_serving_time
; // the earliest time when the controller is ready for new service
uint16_t _request_queue_size
; // number of outstanding requests
queue
<uint32_t> _reply_post_queue
; // reply post queue
queue
<uint32_t> _reply_free_queue
; // reply free queue
event_table_t _etable
; // event table, for recording events
SCSIDisk
*_disk
[IOC_NUM_PORTS
]; // attached disks, one disk per port
pthread_mutex_t _reply_queue_mutex
; // mutex for reply queue
void send_handshake_msg();
void process_handshake_msg();
void send_mpi_msg(uint32_t reply
, bool is_cntx
, uint8_t cntx_type
);
void process_mpi_msg(int entry
, uint32_t fma
);
void doorbell_function_handshake(uint8_t size
);
void doorbell_function_reply_frame_removal();
void doorbell_function_ioc_msg_unit_reset();
void compute_disk_delay(int entry
, int target
, bool wr
);
void scsi_io_done(int entry
, uint32_t reply
, uint8_t is_cntx
, uint8_t cntx_type
, int target
, bool wr
);
void scsi_io_error(int entry
, msg_scsi_io_request_t
*req
, uint16_t ioc_status
);
void process_scsi_cmd(int entry
, msg_scsi_io_request_t
*req
, uint64_t sge_addr
);
void send_page_reply(msg_config_t
*req
, msg_config_reply_t
*reply
, config_page_header_t
*page_header
);
void send_extended_page_reply(msg_config_t
*req
, msg_config_reply_t
*reply
,
config_extended_page_header_t
*extended_page_header
, bool invalid
);
void access_page_manufacturing(msg_config_t
*req
, msg_config_reply_t
*reply
);
void access_page_ioc(msg_config_t
*req
, msg_config_reply_t
*reply
);
void access_page_sas_io_unit(msg_config_t
*req
, msg_config_reply_t
*reply
);
void access_page_sas_device(msg_config_t
*req
, msg_config_reply_t
*reply
);
void access_page_sas_phy(msg_config_t
*req
, msg_config_reply_t
*reply
);
bool memory_space_access(int offset
, bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_door_bell(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_write_sequence(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_host_diagnostic(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_test_base_address(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_diag_rw_data(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_diag_rw_address(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_host_interrupt_status(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_host_interrupt_mask(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_host_request_queue(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_reply_queue(bool wr
, uint64_t *in_buf
, uint8_t size
);
void access_hi_pri_request_queue(bool wr
, uint64_t *in_buf
, uint8_t size
);
void memory_access(uint64_t va
, addrMd_xactnType mode
, void *data
, uint32_t size
, bool wr
);
void memory_transport(uint64_t sge_addr
, addrMd_xactnType sge_addr_mode
, void *data
, uint32_t size
, bool wr
);
void memory_transport(void *sge
, void *data
, uint32_t size
, bool wr
);
void set_doorbell_interrupt();
void set_reply_msg_interrupt();
addrMd_xactnType
mfa_addr_mode() {
return(_ioc_conf
->host_mfa_high_addr
== 0 ? mem_addr32
: mem_addr64
);
uint64_t mfa_addr(uint32_t addr
) {
return(addr
| (_ioc_conf
->host_mfa_high_addr
<< 32));
SAS(const char *modname
, const char *instance_name
);
// callback function for disk io
void io_callback(int entry
);
// override virtual functions from Module class
const char *get_version();
bool parse_arg(const char *);
void module_added(mmi_instance_t
, const char*);
void module_deleted(mmi_instance_t
, const char*);
void *get_interface(const char *name
);
// override virtual function from genericPcieDev
pcieCompleter
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
* samId
);
pcieCompleter
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
* samId
);
pcieCompleter
devif_ioAccess(bool wr
, uint32_t offset
, void * data
, uint8_t be
, \
uint16_t reqId
, uint16_t length
, tlp_X args
,SAM_DeviceId
* samId
);
pcieCompleter
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
* samId
);
void devif_confAccessCb(bool wr
, uint64_t offset
, uint8_t be
);
mmi_instance_t
devif_getInstance() {return instance
;}
const char *devif_getName() {return getName();}
void handle_ui_cmd(int argc
, char * argv
[]);