Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / sas / include / sas.h
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: sas.h
5* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
7*
8* The above named program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public
10* License version 2 as published by the Free Software Foundation.
11*
12* The above named program is distributed in the hope that it will be
13* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with this work; if not, write to the Free Software
19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20*
21* ========== Copyright Header End ============================================
22*/
23#ifndef __SAS_H__
24#define __SAS_H__
25
26#include <queue>
27#include "pcie.h"
28#include "pci_dev.h"
29#include "module.h"
30#include "mpi.h"
31#include "mpi_ioc.h"
32#include "mpi_init.h"
33#include "mpi_cnfg.h"
34#include "disk.h"
35#include "system.h"
36
37
38// ioc parameters
39#define IOC_REPLY_QUEUE_DEPTH 128
40#define IOC_REQ_QUEUE_DEPTH 128
41#define IOC_PRI_QUEUE_DEPTH 128
42#define IOC_REQ_FRAME_SIZE 128
43#define IOC_CHAIN_DEPTH 128
44#define IOC_NUM_PORTS 4
45#define IOC_BLOCK_SIZE 32
46#define IOC_PRODUCTION_ID 101
47#define IOC_CAPABILITIES 0xfc1
48
49
50// port parameters
51#define PORT_TYPE 0x30
52#define PORT_MAX_DEVICES 1
53#define PORT_SCSI_ID 0
54#define PORT_PROTOCOL_FLAGS 0xc
55#define PORT_MAX_POSTED_CMD_BUFFERS 32
56#define PORT_MAX_PERSISTENT_IDS 1
57#define PORT_MAX_LAN_BUCKETS 0
58
59
60// message frame address mask
61#define FMA_ADDRESS_MASK 0xfffffff8
62
63
64// maximal size of message (in byte) received/sent through doorbell handshake
65#define HDSHK_MSG_SIZE 256
66
67
68#define swap_hword(value) \
69 ((uint32_t)(((value) & 0xff) << 8 | (value) >> 8))
70
71#define swap_word(value) \
72 ((uint32_t)((Word)swap_hword((HWord)((value) & 0xffff)) << 16 | \
73 (Word)swap_hword((HWord)((value) >> 16))))
74
75#define swap_lword(value) \
76 ((uint64_t)((((LWord)swap_word(LO_W(value))) << 32) | \
77 ((LWord)swap_word(HI_W(value)))))
78
79
80// system interface register set
81typedef struct {
82 uint32_t doorbell;
83 uint32_t write_seq;
84 uint32_t diag;
85 uint32_t test_base_addr;
86 uint32_t diagrw_data;
87 uint32_t diagrw_addr;
88
89 uint32_t res1[6];
90
91 uint32_t intr_status;
92 uint32_t intr_mask;
93
94 uint32_t res2[2];
95
96 uint32_t req_q;
97 uint32_t reply_q;
98 uint32_t pri_req_q;
99} mpt_reg_t;
100
101
102// ioc configuration
103typedef struct {
104 // assigned by ioc init
105 uint8_t who_init;
106 uint8_t max_devices;
107 uint8_t max_buses;
108 uint16_t reply_frame_size;
109 uint32_t host_mfa_high_addr;
110 uint32_t sense_buffer_high_addr;
111 sge_simple64_t host_page_buffer_sge;
112} ioc_conf_t;
113
114
115class SAS;
116
117
118// event queue callback function
119extern void sas_io_callback(void *arg1, void *arg2);
120
121
122/* event table is used to support diskdelay.
123 It is not a FIFO, because some later request may
124 finish early than an early one.
125
126 allocate an entry: when a request is received.
127 free an entry: when a reply is read.
128*/
129#define EVENT_TABLE_SIZE 128
130
131
132typedef struct {
133 // valid flag
134 uint8_t used;
135
136 // for diskdelay, parameters used to by send_mpi_rely() in the callback function
137 uint32_t reply;
138 uint8_t is_cntx;
139 uint8_t cntx_type;
140
141 // callback function invoke time
142 int64_t invoke_time;
143
144 // done flag
145 uint8_t done;
146} event_table_entry_t;
147
148
149typedef struct {
150 event_table_entry_t events[EVENT_TABLE_SIZE];
151 int next; // next available entry
152
153 void init() {
154 next = 0;
155
156 for (int i = 0; i < EVENT_TABLE_SIZE; i++) {
157 events[i].used = 0;
158 events[i].reply = 0;
159 events[i].is_cntx = 0;
160 events[i].cntx_type = 0;
161 events[i].invoke_time = 0;
162 events[i].done = 0;
163 }
164 }
165
166 void clear() {
167 init();
168 }
169
170 int alloc() {
171 int entry = next;
172
173 for (int i = 0; i < EVENT_TABLE_SIZE; i++) {
174 if (events[entry].used == 0) {
175 events[entry].used = 1;
176 events[entry].reply = 0;
177 events[entry].is_cntx = 0;
178 events[entry].cntx_type = 0;
179 events[entry].invoke_time = 0;
180 events[entry].done = 0;
181
182 next = entry + 1;
183 if (next == EVENT_TABLE_SIZE)
184 next = 0;
185
186 return(entry);
187 }
188 else {
189 entry++;
190 if (entry == EVENT_TABLE_SIZE)
191 entry = 0;
192 }
193 }
194
195 fprintf(stderr, "no free entry in the event table\n");
196 exit(1);
197 }
198
199 void free(int entry) {
200 events[entry].used = 0;
201 }
202
203 void set_invoke_time(int entry, int64_t time) {
204 events[entry].invoke_time = time;
205 }
206
207 int64_t get_invoke_time(int entry) {
208 return(events[entry].invoke_time);
209 }
210
211 void done(int entry, uint32_t reply, uint8_t is_cntx, uint8_t cntx_type) {
212 events[entry].reply = reply;
213 events[entry].is_cntx = is_cntx;
214 events[entry].cntx_type = cntx_type;
215 events[entry].done = 1;
216 }
217
218 void dump(SAS *sasp, FILE *fp) {
219 fprintf(fp, "next_entry %d\n", next);
220 for (int i = 0; i < EVENT_TABLE_SIZE; i++) {
221 fprintf(fp, "event_table[%d] %hhu %u %hhu %hhu %lld %hhu\n", i,
222 events[i].used,
223 events[i].reply,
224 events[i].is_cntx,
225 events[i].cntx_type,
226 events[i].invoke_time,
227 events[i].done);
228 }
229 }
230
231 void restore(SAS *sasp, FILE *fp) {
232 char name[64];
233 fscanf(fp, "%s %d\n", name, &next);
234 for (int i = 0; i < EVENT_TABLE_SIZE; i++) {
235 fscanf(fp, "%s %hhu %u %hhu %hhu %lld %hhu\n", name,
236 &events[i].used,
237 &events[i].reply,
238 &events[i].is_cntx,
239 &events[i].cntx_type,
240 &events[i].invoke_time,
241 &events[i].done);
242 if (events[i].used == 1) {
243 if (events[i].done != 1) {
244 printf("io request for event %d has not been processed yet\n", i);
245 exit(1);
246 }
247 mmi_register_event(events[i].invoke_time, (EventFunc_T*)&sas_io_callback, (void *)sasp, (void *)i);
248 }
249 }
250 }
251} event_table_t;
252
253
254// SAS controller
255class SAS : public genericPcieDev, public Module {
256 const char *fname; // configuration file
257
258 uint32_t _io_base; // io base
259 uint64_t _mem0_base; // mem0 base
260 uint64_t _mem1_base; // mem1 base
261
262 uint8_t _hdshk_msg_req_size; // the size of request msg received through doorbell handshake
263 uint8_t _hdshk_msg_req_recv; // number of bytes received
264 uchar_t *_hdshk_msg_req_buf; // buffer for doorbell handshake request msg
265
266 uint8_t _hdshk_msg_reply_size; // the size of reply msg sent through doorbell handshake
267 uint8_t _hdshk_msg_reply_send; // number of bytes sent
268 uchar_t *_hdshk_msg_reply_buf; // buffer for doorbell handshake reply msg
269
270 mpt_reg_t *_mpt_reg; // system interface register set
271 ioc_conf_t *_ioc_conf; // ioc configuration
272
273 uint8_t *_port_enabled; // port enabled
274
275 int64_t *_earliest_serving_time; // the earliest time when the controller is ready for new service
276
277 uint16_t _request_queue_size; // number of outstanding requests
278 queue<uint32_t> _reply_post_queue; // reply post queue
279 queue<uint32_t> _reply_free_queue; // reply free queue
280
281 event_table_t _etable; // event table, for recording events
282
283 SCSIDisk *_disk[IOC_NUM_PORTS]; // attached disks, one disk per port
284
285 pthread_mutex_t _reply_queue_mutex; // mutex for reply queue
286
287 void reset_ioc();
288
289 void send_handshake_msg();
290 void process_handshake_msg();
291 void send_mpi_msg(uint32_t reply, bool is_cntx, uint8_t cntx_type);
292 void process_mpi_msg(int entry, uint32_t fma);
293
294 void doorbell_function_handshake(uint8_t size);
295 void doorbell_function_reply_frame_removal();
296 void doorbell_function_ioc_msg_unit_reset();
297
298 void compute_disk_delay(int entry, int target, bool wr);
299 void scsi_io_done(int entry, uint32_t reply, uint8_t is_cntx, uint8_t cntx_type, int target, bool wr);
300 void scsi_io_error(int entry, msg_scsi_io_request_t *req, uint16_t ioc_status);
301 void process_scsi_cmd(int entry, msg_scsi_io_request_t *req, uint64_t sge_addr);
302
303 void send_page_reply(msg_config_t *req, msg_config_reply_t *reply, config_page_header_t *page_header);
304 void send_extended_page_reply(msg_config_t *req, msg_config_reply_t *reply,
305 config_extended_page_header_t *extended_page_header, bool invalid);
306 void access_page_manufacturing(msg_config_t *req, msg_config_reply_t *reply);
307 void access_page_ioc(msg_config_t *req, msg_config_reply_t *reply);
308 void access_page_sas_io_unit(msg_config_t *req, msg_config_reply_t *reply);
309 void access_page_sas_device(msg_config_t *req, msg_config_reply_t *reply);
310 void access_page_sas_phy(msg_config_t *req, msg_config_reply_t *reply);
311
312 bool memory_space_access(int offset, bool wr, uint64_t *in_buf, uint8_t size);
313 void access_door_bell(bool wr, uint64_t *in_buf, uint8_t size);
314 void access_write_sequence(bool wr, uint64_t *in_buf, uint8_t size);
315 void access_host_diagnostic(bool wr, uint64_t *in_buf, uint8_t size);
316 void access_test_base_address(bool wr, uint64_t *in_buf, uint8_t size);
317 void access_diag_rw_data(bool wr, uint64_t *in_buf, uint8_t size);
318 void access_diag_rw_address(bool wr, uint64_t *in_buf, uint8_t size);
319 void access_host_interrupt_status(bool wr, uint64_t *in_buf, uint8_t size);
320 void access_host_interrupt_mask(bool wr, uint64_t *in_buf, uint8_t size);
321 void access_host_request_queue(bool wr, uint64_t *in_buf, uint8_t size);
322 void access_reply_queue(bool wr, uint64_t *in_buf, uint8_t size);
323 void access_hi_pri_request_queue(bool wr, uint64_t *in_buf, uint8_t size);
324
325 void memory_access(uint64_t va, addrMd_xactnType mode, void *data, uint32_t size, bool wr);
326 void memory_transport(uint64_t sge_addr, addrMd_xactnType sge_addr_mode, void *data, uint32_t size, bool wr);
327 void memory_transport(void *sge, void *data, uint32_t size, bool wr);
328
329 void set_doorbell_interrupt();
330 void set_reply_msg_interrupt();
331
332 bool msi_enabled();
333
334 addrMd_xactnType mfa_addr_mode() {
335 return(_ioc_conf->host_mfa_high_addr == 0 ? mem_addr32 : mem_addr64);
336 }
337
338 uint64_t mfa_addr(uint32_t addr) {
339 return(addr | (_ioc_conf->host_mfa_high_addr << 32));
340 }
341
342public:
343 SAS(const char *modname, const char *instance_name);
344 ~SAS();
345
346 // callback function for disk io
347 void io_callback(int entry);
348
349 // override virtual functions from Module class
350 const char *get_help();
351 const char *get_version();
352 bool parse_arg(const char *);
353 bool check_args();
354 void init_done();
355 void module_added(mmi_instance_t, const char*);
356 void module_deleted(mmi_instance_t, const char*);
357 void modinfo();
358 void *get_interface(const char *name);
359 bool dump(FILE *fp);
360 bool restore(FILE *fp);
361
362 // override virtual function from genericPcieDev
363 pcieCompleter devif_memAccess(bool wr, uint64_t offset, addrMd_xactnType mode, void * data,\
364 uint16_t length, uint8_t be, uint16_t reqId, tlp_X args,SAM_DeviceId* samId);
365
366 pcieCompleter devif_confAccess(bool wr, uint32_t offset, void * data, \
367 uint8_t be,uint16_t reqId, addrMd_xactnType tType, uint16_t length, tlp_X args,SAM_DeviceId* samId);
368
369 pcieCompleter devif_ioAccess(bool wr, uint32_t offset, void * data, uint8_t be, \
370 uint16_t reqId, uint16_t length, tlp_X args,SAM_DeviceId* samId);
371
372 pcieCompleter devif_msgAccess(uint8_t messageCode, msgRouting route, uint64_t tarIdOrAddr, uint16_t reqId, \
373 void * data, uint16_t length, uint16_t vendorId, uint32_t vendor_data, tlp_X args,SAM_DeviceId* samId);
374
375 void devif_confAccessCb(bool wr, uint64_t offset, uint8_t be);
376
377 mmi_instance_t devif_getInstance() {return instance;}
378
379 const char *devif_getName() {return getName();}
380
381 // other functions
382 void handle_ui_cmd(int argc, char * argv[]);
383
384 void initPci();
385
386};
387
388#endif // __SAS_H__