Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / sas / sas.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: sas.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21/*
22 * "sas.cc" LSI SAS1064E PCIE to 4-Port Serial Attached
23 * SCSI Controller Simulator
24 * Controller-Host interface
25 *
26 * Copyright (C) 2007 Sun Microsystems, Inc.
27 * All rights reserved.
28 *
29 */
30#include "sas.h"
31#include "dr.h"
32#include "fileutil.h"
33
34
35// io space size
36#define IO_SIZE 256
37
38// memory space size
39#define MEM0_SIZE 1024
40#define MEM1_SIZE 65536
41
42// power management capability id register offset
43#define PCI_CONF_PM_CAP_ID 0x44
44
45// MSI capability register offset
46#define PCI_CONF_MSI_CAP_ID 0x50
47
48// SAS simulator general information
49static const char *SAS1064E_Help = "LSISAS1064E PCI Express to 4-port Serial Attached SCSI Controller";
50
51// SAS simulator version
52static const char *SAS1064E_Version = "1.00";
53
54extern "C" char *overlaydir;
55
56extern void overlaydir_cleanup();
57extern char *get_restore_dir();
58
59
60SAS::SAS(const char *modname, const char *instance_name)
61 : Module(modname, instance_name) {
62 debug_info("SAS1064E: creating instance %s\n", instance_name);
63
64 _port_enabled = (uint8_t *)calloc(IOC_NUM_PORTS, sizeof(uint8_t));
65 _earliest_serving_time = (int64_t *)calloc(IOC_NUM_PORTS, sizeof(int64_t));
66 _mpt_reg = (mpt_reg_t *)calloc(1, sizeof(mpt_reg_t));
67 _ioc_conf = (ioc_conf_t *)calloc(1, sizeof(ioc_conf_t));
68
69 _hdshk_msg_req_buf = (uchar_t *)calloc(1, HDSHK_MSG_SIZE);
70 _hdshk_msg_reply_buf = (uchar_t *)calloc(1, HDSHK_MSG_SIZE);
71
72 _hdshk_msg_req_size = 0;
73 _hdshk_msg_req_recv = 0;
74 _hdshk_msg_reply_size = 0;
75 _hdshk_msg_reply_send = 0;
76
77 _request_queue_size = 0;
78
79 while (!_reply_post_queue.empty())
80 _reply_post_queue.pop();
81
82 while (!_reply_free_queue.empty())
83 _reply_free_queue.pop();
84
85 _etable.init();
86
87 pthread_mutex_init(&_reply_queue_mutex, NULL);
88
89 // ioc is in ready state after power-on self-initialization
90 _mpt_reg->doorbell = MPI_IOC_STATE_READY;
91}
92
93
94SAS::~SAS() {
95 debug_info("SAS1064E: deleting instance %s\n", instance_name);
96 free(_port_enabled);
97 free(_earliest_serving_time);
98 free(_mpt_reg);
99 free(_ioc_conf);
100 free(_hdshk_msg_req_buf);
101 free(_hdshk_msg_reply_buf);
102
103 pthread_mutex_destroy(&_reply_queue_mutex);
104
105 for (int i = 0; i < IOC_NUM_PORTS; i++) {
106 if (_disk[i]) {
107 _disk[i]->delete_overlays();
108 free(_disk[i]);
109 }
110 }
111}
112
113
114const char *SAS::get_help() {
115 return Module::get_help_string();
116}
117
118
119const char *SAS::get_version() {
120 return SAS1064E_Version;
121}
122
123
124bool SAS::parse_arg(const char *arg) {
125 if (argval("targets", arg, &fname)){
126 debug_info("%s: targets=<%s>\n", HERE, fname);
127 return true;
128 }
129
130 return dev_parse_arg(arg);
131}
132
133
134bool SAS::check_args(){
135 if (dev_check_args()) {
136 return true;
137 }
138
139 return false;
140}
141
142
143void SAS::initPci() {
144 char reg_descr[100];
145
146 snprintf(reg_descr,100,"%s LSISAS1064E Vendor ID", getName());
147 confSpace->addConfReg(new pciConfReg(reg_descr,2,0x1000,0x0000,0x0),PCI_CONF_VENID);
148
149 snprintf(reg_descr,100,"%s LSISAS1064E Device ID", getName());
150 confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0056,0x0000,0x0),PCI_CONF_DEVID);
151
152 snprintf(reg_descr,100,"%s LSISAS1064E Command", getName());
153 confSpace->addConfReg(new pcieCommandReg(reg_descr,(genericPcieDev *)this,0x0757),PCI_CONF_COMM);
154
155 snprintf(reg_descr,100,"%s LSISAS1064E Status", getName());
156 confSpace->addConfReg(new pcieStatusReg(reg_descr,(genericPcieDev *)this,0x0230,0xff38),PCI_CONF_STAT);
157
158 snprintf(reg_descr,100,"%s LSISAS1064E Rev Id",getName());
159 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x03,0x00),PCI_CONF_REVID);
160
161 snprintf(reg_descr,100,"%s LSISAS1064E prog class",getName());
162 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_PROGCLASS);
163
164 snprintf(reg_descr,100,"%s LSISAS1064E Sub Class",getName());
165 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_SUBCLASS);
166
167 snprintf(reg_descr,100,"%s LSISAS1064E Base Class",getName());
168 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x01,0x00),PCI_CONF_BASCLASS);
169
170 snprintf(reg_descr,100,"%s LSISAS1064E Cache Line Size",getName());
171 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xf8),PCI_CONF_CACHE_LINESZ);
172
173 snprintf(reg_descr,100,"%s LSISAS1064E Latency Timer",getName());
174 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xf0),PCI_CONF_LATENCY_TIMER);
175
176 snprintf(reg_descr,100,"%s LSISAS1064E Header Type",getName());
177 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_HEADER);
178
179 snprintf(reg_descr,100,"%s LSISAS1064E BAR0 - IO",getName());
180 confSpace->addConfReg(new pcieBaseAddrReg(reg_descr,(genericPcieDev *)this,IO_SIZE,PCIE_IO, false, false),PCI_CONF_BASE0); //256 bytes
181
182 snprintf(reg_descr,100,"%s LSISAS1064E BAR1 MEM64 0",getName());
183 confSpace->addConfReg(new pcieBaseAddrReg(reg_descr,(genericPcieDev *)this,MEM0_SIZE,PCIE_MEM, false, false),PCI_CONF_BASE1); //1024 bytes
184
185 snprintf(reg_descr,100,"%s LSISAS1064E BAR3 MEM64 1",getName());
186 confSpace->addConfReg(new pcieBaseAddrReg(reg_descr,(genericPcieDev *)this,MEM1_SIZE,PCIE_MEM, false, false),PCI_CONF_BASE3); //64k bytes
187
188 snprintf(reg_descr,100,"%s LSISAS1064E susbsystem vendor id",getName());
189 confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0000,0x0000),PCI_CONF_SUBVENID);
190
191 snprintf(reg_descr,100,"%s LSISAS1064E susbsystem id",getName());
192 confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0000,0x0000),PCI_CONF_SUBSYSID);
193
194 snprintf(reg_descr,100,"%s LSISAS1064E ROM base addr",getName());
195 confSpace->addConfReg(new pciConfReg(reg_descr,4,0x00000000,0x0),PCI_CONF_ROM);
196
197 snprintf(reg_descr,100,"%s LSISAS1064E capabilities pointer",getName());
198 confSpace->addConfReg(new pciConfReg(reg_descr,1,PCI_CONF_PM_CAP_ID,0x00),PCI_CONF_CAP_PTR);
199
200 snprintf(reg_descr,100,"%s LSISAS1064E Intr Line",getName());
201 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),PCI_CONF_ILINE);
202
203 snprintf(reg_descr,100,"%s LSISAS1064E Intr Pin",getName());
204 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x01,0x00),PCI_CONF_IPIN);
205
206 snprintf(reg_descr,100,"%s LSISAS1064E Min Grant",getName());
207 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_MIN_G);
208
209 snprintf(reg_descr,100,"%s LSISAS1064E Max Lat",getName());
210 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_MAX_L);
211
212 // power management capability
213 snprintf(reg_descr,100,"%s LSISAS1064E Power Mgmt Cap ID",getName());
214 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x01,0x00),PCI_CONF_PM_CAP_ID);
215
216 snprintf(reg_descr,100,"%s LSISAS1064E Power Mgmt Next Pointer",getName());
217 confSpace->addConfReg(new pciConfReg(reg_descr,1,PCI_CONF_MSI_CAP_ID,0x00),PCI_CONF_PM_CAP_ID+PCI_CAP_NEXT_PTR);
218
219 snprintf(reg_descr,100,"%s LSISAS1064E Power Mgmt Capabilities",getName());
220 confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0202,0x0000),PCI_CONF_PM_CAP_ID+PCI_PMCAP);
221
222 snprintf(reg_descr,100,"%s LSISAS1064E Power Mgmt CSR",getName());
223 confSpace->addConfReg(new pciConfReg(reg_descr,2,0x0000,0x0000),PCI_CONF_PM_CAP_ID+PCI_PMCSR);
224
225 snprintf(reg_descr,100,"%s LSISAS1064E Power Mgmt CSR Bridge Support Extension",getName());
226 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_PM_CAP_ID+PCI_PMCSR_BSE);
227
228 snprintf(reg_descr,100,"%s LSISAS1064E Power Mgmt Data",getName());
229 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_PM_CAP_ID+PCI_PMDATA);
230
231 // MSI capability
232 addMsiCap(0x0,PCI_CONF_MSI_CAP_ID,0x0080);
233
234 snprintf(reg_descr,100,"%s LSISAS1064E MSI Reserved",getName());
235 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_MSI_CAP_ID+0xe);
236
237 snprintf(reg_descr,100,"%s LSISAS1064E MSI Mask Bits",getName());
238 confSpace->addConfReg(new pciConfReg(reg_descr,4,0x00000000,0xffffffff),PCI_CONF_MSI_CAP_ID+0x10);
239
240 snprintf(reg_descr,100,"%s LSISAS1064E MSI Pending Bits",getName());
241 confSpace->addConfReg(new pciConfReg(reg_descr,4,0x00000000,0x00000000),PCI_CONF_MSI_CAP_ID+0x14);
242}
243
244
245void SAS::handle_ui_cmd(int argc, char * argv[]) {
246 if (argc == 1) {
247 printf("%s supports following UI commands\n",getName());
248 printf("%s debug [<level>]\n\
249 set the debug level for debug prints to \'level\'\n\
250 if \'level\' not provided, print current debug level\n\
251 \'level\' = [0|1|2]\n", getName());
252 printf("%s disk\n\
253 show all attached disks\n", getName());
254 } else if (!strcmp(argv[1], "debug")) {
255 if(argv[2]){
256 int level = atoi(argv[2]);
257 if (level != 0 && level != 1 && level != 2)
258 debug_err("%s: unsupported debug level <%s>\n", getName(), argv[2]);
259 else {
260 debug_level = level;
261 confSpace->set_debug_level(debug_level);
262 printf("%s: set debug level to %d\n", getName(), debug_level);
263 }
264 }else
265 printf("%s: current debug level %d\n", getName(), debug_level);
266 } else if (!strcmp(argv[1], "disk")) {
267 printf("attached disks:\n");
268 for (int i = 0; i < IOC_NUM_PORTS; i++)
269 if (_disk[i])
270 printf("%s is attached to target %d\n", _disk[i]->get_name(), i);
271 }
272 else {
273 debug_err("%s: unsupported UI command <%s>\n", getName(), argv[1]);
274 }
275}
276
277
278int sas_ui_cmd(void *obj, int argc, char * argv[]){
279 SAS *sas = dynamic_cast<SAS *>((Module *)obj);
280 sas->handle_ui_cmd(argc, argv);
281 return(0);
282}
283
284
285void SAS::init_done(){
286 // create disk overlay
287 if (!isDir(overlaydir)) {
288 int status = mkdir(overlaydir, 0777);
289 if (status != 0) {
290 debug_err("%s: Unable to create disk overlay dir: %s (%s)\n", getName(), overlaydir, strerror(errno));
291 exit(1);
292 }
293
294 // .nsr is created in overlay directory to avoid backup of shadow files
295 char *fname = (char *)malloc(strlen(overlaydir) + 6);
296 sprintf(fname, "%s/.nsr", overlaydir);
297 FILE *fp = fopen(fname, "w");
298 if (fp == NULL) {
299 debug_err("%s: Unable to creat .nsr in %s (%s)\n", getName(), overlaydir, strerror(errno));
300 exit(1);
301 }
302 fprintf(fp, "+null: * .?*\n");
303 fclose(fp);
304 free(fname);
305
306 status = atexit(overlaydir_cleanup);
307 if (status != 0) {
308 debug_err("%s: Unable to register cleanup function for overlay dir: %s (%s)\n", getName(), overlaydir, strerror(errno));
309 exit(1);
310 }
311 }
312
313 // attach disks
314 for (int i = 0; i < IOC_NUM_PORTS; i++)
315 _disk[i] = NULL;
316
317 FILE *fp = NULL;
318
319 // open disk configuration file, try the restore directory first
320 char *restore_dir = get_restore_dir();
321 if (restore_dir) {
322 // need to extract file name
323 int i;
324 for (i = strlen(fname) - 1; i >= 0; i--)
325 if (fname[i] == '/')
326 break;
327 char *name = strdup(&fname[i+1]);
328
329 // open it if it is in the restore directory
330 char *dev_name = (char *)getName();
331 char *rname = (char *)malloc(strlen(restore_dir) + strlen(dev_name) + strlen(name) + 15);
332 sprintf(rname, "%s/sas_ctrl_%s/%s", restore_dir, dev_name, name);
333
334 fp = fopen(rname, "r");
335
336 if (!fp)
337 debug_info("%s: can't find sas disk configuration file: %s in the restore directory\n", getName(), name);
338 else {
339 // update fname with rname
340 if (strlen(fname) < strlen(rname)) {
341 free((void *)fname);
342 fname = strdup(rname);
343 }
344 else
345 strcpy((char *)fname, rname);
346 }
347
348 free(name);
349 free(rname);
350 }
351
352 // open disk configuration file, try the one specified in .rc file next
353 if (!fp)
354 fp = fopen(fname, "r");
355
356 if (!fp) {
357 debug_err("%s: can't find sas disk configuration file: %s\n", getName(), fname);
358 exit(1);
359 }
360
361 for (int target_id = 0; target_id < IOC_NUM_PORTS; target_id++) {
362 SCSIDisk *disk = new SCSIDisk;
363
364 // disk name is constructed as controller name + "t" + tatget_id
365 char disk_name[64];
366 sprintf(disk_name, "%st%d", getName(), target_id);
367
368 disk->set_name(disk_name);
369 disk->set_target(target_id);
370
371 disk->parse_config(fname, fp, target_id);
372 if (disk->get_num_partitions() == 0) {
373 delete disk;
374 continue;
375 }
376
377 _disk[target_id] = disk;
378 debug_info("%s: disk %s is attached as target %d, total number of partitons: %d\n",
379 getName(), disk->get_name(), disk->get_target_id(), disk->get_num_partitions());
380 }
381
382 fclose(fp);
383
384 // register ui commands
385 mmi_register_instance_cmd(getInstance(), get_help(), sas_ui_cmd);
386
387
388 // initialize pci registers
389 initPci();
390 dev_init_done(Module::debug_level);
391}
392
393
394void SAS::module_added(mmi_instance_t target, const char *target_name) {
395 dev_module_added(target_name);
396}
397
398
399void SAS::module_deleted(mmi_instance_t target, const char *target_name) {
400 dev_module_deleted(target_name);
401}
402
403
404void SAS::modinfo() {
405 printf("%s is a %s\n", getName(), SAS1064E_Help);
406 printf(" Vendor id <0x%lx>, Device id <0x%lx>\n", confSpace->readConf(PCI_CONF_VENID), confSpace->readConf(PCI_CONF_DEVID));
407 printf(" Upstream pcie bus is <%s>\n", busName);
408 printf(" Disk configuration file is <%s>\n", fname);
409 printf(" Type \'%s\' for the description of supported UI commands\n", getName());
410}
411
412
413void *SAS::get_interface(const char *name) {
414 if (!strcmp(name, GENERIC_PCIE_DEV_INTERFACE))
415 return (genericPcieDevIf*)this;
416 else
417 return NULL;
418}
419
420
421void SAS::reset_ioc() {
422 // clear all registers
423 bzero(_mpt_reg, sizeof(mpt_reg_t));
424
425 // clear ioc configuration
426 bzero(_ioc_conf, sizeof(ioc_conf_t));
427
428 // clear earliest serving time
429 bzero(_earliest_serving_time, sizeof(uint64_t) * IOC_NUM_PORTS);
430
431 // diable ports
432 bzero(_port_enabled, sizeof(uint8_t) * IOC_NUM_PORTS);
433
434 // clear handshake messages
435 bzero(_hdshk_msg_req_buf, HDSHK_MSG_SIZE);
436 bzero(_hdshk_msg_reply_buf, HDSHK_MSG_SIZE);
437 _hdshk_msg_req_size = 0;
438 _hdshk_msg_req_recv = 0;
439 _hdshk_msg_reply_size = 0;
440 _hdshk_msg_reply_send = 0;
441
442 // clear queues
443 _request_queue_size = 0;
444
445 while (!_reply_post_queue.empty())
446 _reply_post_queue.pop();
447
448 while (!_reply_free_queue.empty())
449 _reply_free_queue.pop();
450
451 // clear event table
452 _etable.clear();
453
454 // set ioc to ready state
455 _mpt_reg->doorbell = (_mpt_reg->doorbell & ~MPI_IOC_STATE_MASK) |
456 MPI_IOC_STATE_READY;
457
458 // set interrupt masks
459 _mpt_reg->intr_mask |= MPI_HIM_DIM;
460 _mpt_reg->intr_mask |= MPI_HIM_RIM;
461}
462
463
464pcieCompleter SAS::devif_confAccess(bool wr, uint32_t offset, void * data, \
465 uint8_t be,uint16_t reqId, addrMd_xactnType tType, uint16_t length, tlp_X args,SAM_DeviceId* id) {
466 bool ret;
467 int size = byteEnabletoSize(be); // length is the number of words
468
469 if(id)*id = samId;
470
471 if (wr) {
472 *(uint64_t*)data &= 0xFFFFFFFF;
473 uint32_t l_buf = *(uint64_t*)data;
474 if(size == 4){
475 *(uint64_t*)data = swap_word(l_buf);
476 }else if(size == 2){
477 *(uint64_t*)data = swap_hword(l_buf);
478 }else if (size == 1)
479 *(uint64_t*)data = l_buf;
480 debug_info("%s: conf xactn type 0: offset <0x%x> wr size<%d> be<0x%x> data<0x%llx>\n",
481 getName(), offset, size, be,*(uint64_t*)data);
482 }
483
484 ret = confSpace->confAccessSize(offset, wr, (uint64_t *)data, size);
485 if (wr) debug_info("\n");
486 if (!wr) {
487 uint32_t l_buf = *(uint64_t*)data;
488 if(size == 4){
489 *(uint64_t*)data = swap_word(l_buf & 0xFFFFFFFF);
490 }else if(size == 2){
491 *(uint64_t*)data = swap_hword(l_buf & 0xFFFF);
492 }else if (size == 1)
493 *(uint64_t*)data = l_buf & 0xFF;
494
495 debug_info("%s: conf xactn type 0: offset <0x%x> rd size<%d> be<0x%x> data<0x%llx>\n",
496 getName(), offset, size, be, *(uint64_t*)data);
497 debug_info("\n");
498 }
499
500 devif_confAccessCb(wr,offset,be);
501 return (ret ? pcieCompleter(SC,getId()) : pcieCompleter(CA,getId()));
502}
503
504
505void SAS::devif_confAccessCb(bool wr, uint64_t offset, uint8_t be) {
506 if(!wr)
507 return;
508
509 if(offset == PCI_CONF_BASE0){
510 _io_base = confSpace->readConf(offset) & 0xfffffffc;
511 }else if (offset == PCI_CONF_BASE1 || offset == PCI_CONF_BASE2){
512 pcieBaseAddrReg * r = (pcieBaseAddrReg*)confSpace->getConfReg(PCI_CONF_BASE1);
513 _mem0_base = ((uint64_t)(r->val_32To63)) << 32 |(r->getVal() & 0xfffffff0) ;
514 }else if (offset == PCI_CONF_BASE3 || offset == PCI_CONF_BASE4){
515 pcieBaseAddrReg * r = (pcieBaseAddrReg*)confSpace->getConfReg(PCI_CONF_BASE3);
516 _mem1_base = ((uint64_t)(r->val_32To63)) << 32 |(r->getVal() & 0xfffffff0) ;
517 }
518}
519
520
521//
522bool SAS::msi_enabled() {
523 uint16_t msi_msg_ctrl = confSpace->readConf(PCI_CONF_MSI_CAP_ID + MSI_MSGCNTRL_OFFSET);
524 return(msi_msg_ctrl & 0x1);
525}
526
527
528// called whenever IOC writes a value to doorbell
529void SAS::set_doorbell_interrupt() {
530 bool pending = _mpt_reg->intr_status & MPI_HIS_DOORBELL_INTERRUPT;
531
532 // set doorbell interrupt bit
533 _mpt_reg->intr_status |= MPI_HIS_DOORBELL_INTERRUPT;
534
535 // send interrupt if it is unmasked and no pending doorbell interrupt
536 if (!(_mpt_reg->intr_mask & MPI_HIM_DIM) && !pending) {
537 if (msi_enabled()) {
538 // send MSI
539 debug_info("%s: send doorbell MSI\n", getName());
540 uint32_t lo = confSpace->readConf(PCI_CONF_MSI_CAP_ID + MSI_MSGADDR0_OFFSET);
541 uint32_t hi = confSpace->readConf(PCI_CONF_MSI_CAP_ID + MSI_MSGADDR1_OFFSET);
542 uint64_t msi_addr = ((uint64_t)hi << 32) | lo;
543 uint32_t msi_data = confSpace->readConf(PCI_CONF_MSI_CAP_ID + MSI_MSGDATA64_OFFSET);
544
545 pcieCompleter status = busIf->busif_access(PCIE_MEM, true, msi_addr, (void*)&msi_data,
546 1, 0xf, getId(), mem_addr64, &samId);
547
548 if (handleCompletion(status) == -1) {
549 debug_err("%s: pcie error when sending doorbell MSI\n");
550 exit(1);
551 }
552 }
553 else {
554 // send INTx
555 debug_info("%s: send doorbell INTx\n", getName());
556
557 pcieCompleter status = busIf->busif_msgAccess((uint8_t)MSG_Assert_INTA, local, getId(),&samId);
558
559 if (handleCompletion(status) == -1) {
560 debug_err("%s: pcie error when sending doorbell INTx\n");
561 exit(1);
562 }
563 }
564 }
565}
566
567
568// called whenever IOC writes a reply msg descriptor to reply post queue
569void SAS::set_reply_msg_interrupt() {
570 bool pending = _mpt_reg->intr_status & MPI_HIS_REPLY_MESSAGE_INTERRUPT;
571
572 // set reply msg interrupt bit
573 _mpt_reg->intr_status |= MPI_HIS_REPLY_MESSAGE_INTERRUPT;
574
575 // send interrupt if it is unmasked and no pending reply msg interrupt
576 if (!(_mpt_reg->intr_mask & MPI_HIM_RIM) && !pending) {
577 if (msi_enabled()) {
578 // send MSI
579 debug_info("%s: send reply msg MSI\n", getName());
580 uint32_t lo = confSpace->readConf(PCI_CONF_MSI_CAP_ID + MSI_MSGADDR0_OFFSET);
581 uint32_t hi = confSpace->readConf(PCI_CONF_MSI_CAP_ID + MSI_MSGADDR1_OFFSET);
582 uint64_t msi_addr = ((uint64_t)hi << 32) | lo;
583 uint32_t msi_data = confSpace->readConf(PCI_CONF_MSI_CAP_ID + MSI_MSGDATA64_OFFSET);
584
585 pcieCompleter status = busIf->busif_access(PCIE_MEM, true, msi_addr, (void*)&msi_data,
586 1, 0xf, getId(), mem_addr64, &samId);
587
588 if (handleCompletion(status) == -1) {
589 debug_err("%s: pcie error when sending reply msg MSI\n");
590 exit(1);
591 }
592 }
593 else {
594 // send INTx
595 debug_info("%s: send reply msg INTx\n", getName());
596
597 pcieCompleter status = busIf->busif_msgAccess((uint8_t)MSG_Assert_INTA, local, getId(),&samId);
598
599 if (handleCompletion(status) == -1) {
600 debug_err("%s: pcie error when sending reply msg INTx\n");
601 exit(1);
602 }
603 }
604 }
605}
606
607
608void SAS::doorbell_function_handshake(uint8_t size) {
609 // set by ioc to indicate it starts to perform a doorbell function
610 _mpt_reg->doorbell |= MPI_DOORBELL_USED;
611
612 // clear to indicate ioc has read the message
613 _mpt_reg->intr_status &= ~MPI_HIS_IOP_DOORBELL_STATUS;
614
615 // set the size of total and received handhake message (in dword)
616 bzero(_hdshk_msg_req_buf, HDSHK_MSG_SIZE);
617 assert(size > 0 && size <= HDSHK_MSG_SIZE >> 2);
618 _hdshk_msg_req_size = size;
619 _hdshk_msg_req_recv = 0;
620
621 // set by ioc after the doorbell is written
622 set_doorbell_interrupt();
623}
624
625
626void SAS::doorbell_function_reply_frame_removal() {
627 // set by ioc to indicate it starts to perform a doorbell function
628 _mpt_reg->doorbell |= MPI_DOORBELL_USED;
629
630 // clear to indicate ioc has read the message
631 _mpt_reg->intr_status &= ~MPI_HIS_IOP_DOORBELL_STATUS;
632
633 // use doorbell to send the reply message
634 *((uint32_t *)_hdshk_msg_reply_buf) = SAM_LE_32(_reply_free_queue.size());
635
636 _hdshk_msg_reply_size = 1;
637 while (!_reply_free_queue.empty()) {
638 *((uint32_t *)_hdshk_msg_reply_buf + _hdshk_msg_reply_size) = SAM_LE_32(_reply_free_queue.front());
639 _reply_free_queue.pop();
640 _hdshk_msg_reply_size++;
641 }
642
643 uint16_t value;
644
645 // set the size of message to be sent in hword
646 _hdshk_msg_reply_size = _hdshk_msg_reply_size << 1;
647 _hdshk_msg_reply_send = 0;
648
649 // put the first hword in the doorbell
650 value = *(uint16_t *)(_hdshk_msg_reply_buf + (_hdshk_msg_reply_send << 1));
651 value = SAM_LE_16(value);
652 _mpt_reg->doorbell = (_mpt_reg->doorbell & ~MPI_DOORBELL_DATA_MASK) | value;
653 _hdshk_msg_reply_send++;
654
655 // set by ioc after the doorbell is written
656 set_doorbell_interrupt();
657}
658
659
660void SAS::doorbell_function_ioc_msg_unit_reset() {
661 // set by ioc to indicate it starts to perform a doorbell function
662 _mpt_reg->doorbell |= MPI_DOORBELL_USED;
663
664 // clear to indicate ioc has read the message
665 _mpt_reg->intr_status &= ~MPI_HIS_IOP_DOORBELL_STATUS;
666
667 // clear queues
668 while (!_reply_post_queue.empty())
669 _reply_post_queue.pop();
670
671 while (!_reply_free_queue.empty())
672 _reply_free_queue.pop();
673
674 // clear event table
675 _etable.clear();
676
677 // set ioc to ready state
678 _mpt_reg->doorbell = (_mpt_reg->doorbell & ~MPI_IOC_STATE_MASK) |
679 MPI_IOC_STATE_READY;
680
681 // clear to indicate ioc finishes doorbell function
682 _mpt_reg->doorbell &= ~MPI_DOORBELL_USED;
683}
684
685
686void SAS::access_door_bell(bool wr, uint64_t *in_buf, uint8_t size) {
687 if (wr) {
688 uint32_t value = *in_buf;
689
690 // request messages received through doorbell handshake
691 // message is written in 4 bytes chunk using little endian model
692 if (_hdshk_msg_req_recv < _hdshk_msg_req_size) {
693 *((uint32_t *)(_hdshk_msg_req_buf + (_hdshk_msg_req_recv << 2))) = SAM_LE_32(value);
694 _mpt_reg->intr_status &= ~MPI_HIS_IOP_DOORBELL_STATUS;
695 _hdshk_msg_req_recv++;
696 if (_hdshk_msg_req_recv == _hdshk_msg_req_size) {
697 process_handshake_msg();
698 _hdshk_msg_req_size = 0;
699 _hdshk_msg_req_recv = 0;
700 }
701 return;
702 }
703
704 // doorbell function
705 uint32_t d_fun = (value & MPI_DOORBELL_FUNCTION_MASK) >> MPI_DOORBELL_FUNCTION_SHIFT;
706
707 switch (d_fun) {
708 case MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET:
709 doorbell_function_ioc_msg_unit_reset();
710 break;
711
712 case MPI_FUNCTION_IO_UNIT_RESET:
713 debug_err("%s: MPI_FUNCTION_IO_UNIT_RESET no impl\n", getName());
714 exit(1);
715 break;
716
717 case MPI_FUNCTION_HANDSHAKE:
718 doorbell_function_handshake((value & MPI_DOORBELL_ADD_DWORDS_MASK) >>
719 MPI_DOORBELL_ADD_DWORDS_SHIFT);
720 break;
721
722 case MPI_FUNCTION_REPLY_FRAME_REMOVAL:
723 doorbell_function_reply_frame_removal();
724 break;
725
726 case MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL:
727 debug_err("%s: MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL no impl\n", getName());
728 exit(1);
729 break;
730
731 default:
732 debug_err("%s: unknown doorbell function\n", getName());
733 exit(1);
734 break;
735 }
736 }
737 else {
738 *in_buf = _mpt_reg->doorbell;
739 }
740}
741
742
743void SAS::access_write_sequence(bool wr, uint64_t *in_buf, uint8_t size) {
744 uint32_t key_value = *in_buf & MPI_WRSEQ_KEY_VALUE_MASK;
745
746 if (!wr) {
747 debug_err("%s: write sequence register is write only!\n", getName());
748 return;
749 }
750
751 // A sequence of values have to be written before Host Diagnostic register is accessed.
752 // Any incorrect value will cause the restart of matching process.
753 switch (key_value) {
754 case MPI_WRSEQ_1ST_KEY_VALUE:
755 // disable host diag write if it is set
756 if (_mpt_reg->write_seq == MPI_WRSEQ_5TH_KEY_VALUE)
757 _mpt_reg->diag &= ~MPI_DIAG_DRWE;
758
759 // a new sequence starts
760 _mpt_reg->write_seq = key_value;
761
762 break;
763
764 case MPI_WRSEQ_2ND_KEY_VALUE:
765 // disable host diag write if it is set
766 if (_mpt_reg->write_seq == MPI_WRSEQ_5TH_KEY_VALUE)
767 _mpt_reg->diag &= ~MPI_DIAG_DRWE;
768
769 if (_mpt_reg->write_seq == MPI_WRSEQ_1ST_KEY_VALUE)
770 _mpt_reg->write_seq = key_value;
771 else {
772 _mpt_reg->write_seq = 0;
773 }
774
775 break;
776
777 case MPI_WRSEQ_3RD_KEY_VALUE:
778 // disable host diag write if it is set
779 if (_mpt_reg->write_seq == MPI_WRSEQ_5TH_KEY_VALUE)
780 _mpt_reg->diag &= ~MPI_DIAG_DRWE;
781
782 if (_mpt_reg->write_seq == MPI_WRSEQ_2ND_KEY_VALUE)
783 _mpt_reg->write_seq = key_value;
784 else {
785 _mpt_reg->write_seq = 0;
786 }
787
788 break;
789
790 case MPI_WRSEQ_4TH_KEY_VALUE:
791 // disable host diag write if it is set
792 if (_mpt_reg->write_seq == MPI_WRSEQ_5TH_KEY_VALUE)
793 _mpt_reg->diag &= ~MPI_DIAG_DRWE;
794
795 if (_mpt_reg->write_seq == MPI_WRSEQ_3RD_KEY_VALUE)
796 _mpt_reg->write_seq = key_value;
797 else {
798 _mpt_reg->write_seq = 0;
799 }
800
801 break;
802
803
804 case MPI_WRSEQ_5TH_KEY_VALUE:
805 // disable host diag write if it is set
806 if (_mpt_reg->write_seq == MPI_WRSEQ_5TH_KEY_VALUE)
807 _mpt_reg->diag &= ~MPI_DIAG_DRWE;
808
809 if (_mpt_reg->write_seq == MPI_WRSEQ_4TH_KEY_VALUE)
810 _mpt_reg->write_seq = key_value;
811 else {
812 _mpt_reg->write_seq = 0;
813 }
814
815 // enable host diag write
816 if (_mpt_reg->write_seq == MPI_WRSEQ_5TH_KEY_VALUE)
817 _mpt_reg->diag |= MPI_DIAG_DRWE;
818
819 break;
820
821 default:
822 _mpt_reg->write_seq = 0;
823 _mpt_reg->diag &= ~MPI_DIAG_DRWE;
824 break;
825 }
826}
827
828
829void SAS::access_host_diagnostic(bool wr, uint64_t *in_buf, uint8_t size) {
830 if (wr) {
831 uint32_t value = *in_buf & 0x7ff;
832 _mpt_reg->diag = value;
833
834 if (value & MPI_DIAG_RESET_ADAPTER) {
835 reset_ioc();
836 _mpt_reg->diag &= ~MPI_DIAG_RESET_ADAPTER;
837 }
838 }
839 else {
840 *in_buf = _mpt_reg->diag;
841 }
842}
843
844
845void SAS::access_test_base_address(bool wr, uint64_t *in_buf, uint8_t size) {
846 if (wr) {
847 _mpt_reg->test_base_addr = *in_buf;
848 }
849 else {
850 *in_buf = _mpt_reg->test_base_addr;
851 }
852}
853
854
855void SAS::access_diag_rw_data(bool wr, uint64_t *in_buf, uint8_t size) {
856 if (wr) {
857 _mpt_reg->diagrw_data = *in_buf;
858 }
859 else {
860 *in_buf = _mpt_reg->diagrw_data;
861 }
862}
863
864
865void SAS::access_diag_rw_address(bool wr, uint64_t *in_buf, uint8_t size) {
866 if (wr) {
867 _mpt_reg->diagrw_addr = *in_buf;
868 }
869 else {
870 *in_buf = _mpt_reg->diagrw_addr;
871 }
872}
873
874
875void SAS::access_host_interrupt_status(bool wr, uint64_t *in_buf, uint8_t size) {
876 if (wr) {
877 uint32_t l_buf = *in_buf;
878
879 if (!msi_enabled()) {
880 // deassert interrupt
881 if (_mpt_reg->intr_status & MPI_HIS_DOORBELL_INTERRUPT) {
882 // don't deassert interrupt if reply msg interrupt is set
883 if ((_mpt_reg->intr_status & MPI_HIS_REPLY_MESSAGE_INTERRUPT) == 0) {
884 debug_info("%s: deassert interrupt\n", getName());
885 pcieCompleter status = busIf->busif_msgAccess((uint8_t)MSG_Deassert_INTA, local, getId(),&samId);
886 if (handleCompletion(status) == -1) {
887 debug_err("%s: pcie error when deasserting doorbell interrupt\n");
888 exit(1);
889 }
890 }
891 }
892 }
893
894 // reply msg interrupt is not cleared by ANY write
895 _mpt_reg->intr_status = l_buf | (_mpt_reg->intr_status & MPI_HIS_REPLY_MESSAGE_INTERRUPT);
896
897 // doorbell interrupt is always cleared by ANY write
898 _mpt_reg->intr_status &= ~MPI_HIS_DOORBELL_INTERRUPT;
899
900 // reply messages sent through doorbell handshake
901 if ((_mpt_reg->intr_status & MPI_HIS_DOORBELL_INTERRUPT) == 0) {
902 if (_hdshk_msg_reply_send < _hdshk_msg_reply_size) {
903 uint32_t value = SAM_LE_16(*(uint16_t *)(_hdshk_msg_reply_buf + (_hdshk_msg_reply_send << 1)));
904 _mpt_reg->doorbell = (_mpt_reg->doorbell & ~MPI_DOORBELL_DATA_MASK) | value;
905
906 _hdshk_msg_reply_send++;
907
908 // set by ioc after the doorbell is written
909 set_doorbell_interrupt();
910 }
911 else if (_hdshk_msg_reply_send > 0 && _hdshk_msg_reply_send == _hdshk_msg_reply_size) {
912 _hdshk_msg_reply_size = 0;
913 _hdshk_msg_reply_send = 0;
914
915 // clear to indicate ioc finishes doorbell function
916 _mpt_reg->doorbell &= ~MPI_DOORBELL_USED;
917
918 // set by ioc after the doorbell is written
919 set_doorbell_interrupt();
920 }
921 }
922 }
923 else {
924 *in_buf = _mpt_reg->intr_status;
925 }
926}
927
928
929void SAS::access_host_interrupt_mask(bool wr, uint64_t *in_buf, uint8_t size) {
930 if (wr) {
931 // In some very rare cases, target probe starts (which masks the interrupt)
932 // while ioc is still processing a scsi cmd. We avoid mask in such cases.
933 bool pending_cmd = false;
934 for (int i = 0; i < EVENT_TABLE_SIZE; i++) {
935 if (_etable.events[i].used) {
936 pending_cmd = true;
937 break;
938 }
939 }
940 if (pending_cmd) {
941 debug_info("%s: ioc is busy, reply msg interrupt will not be masked \n", getName());
942 _mpt_reg->intr_mask = (_mpt_reg->intr_mask & MPI_HIM_RIM) | (*in_buf & ~MPI_HIM_RIM);
943 }
944 else {
945 _mpt_reg->intr_mask = *in_buf;
946 }
947 }
948 else {
949 *in_buf = _mpt_reg->intr_mask;
950 }
951}
952
953
954void SAS::access_host_request_queue(bool wr, uint64_t *in_buf, uint8_t size) {
955 if (wr) {
956 uint32_t l_buf = *in_buf;
957 // request is processed immediately after it is received,
958 // so request post queue is not needed.
959 _request_queue_size++;
960
961 // timing model is done through event table
962 int entry = _etable.alloc();
963
964 // process io request
965 process_mpi_msg(entry, l_buf);
966
967 int64_t invoke_time = _etable.get_invoke_time(entry);
968 int64_t current_time = mmi_get_time();
969
970 debug_info("%s: io request is received, current time is %lld\n", getName(), current_time);
971
972 if (invoke_time == current_time) {
973 // no disk delay is simulated, finish it immediately
974 sas_io_callback((void *)this, (void*)entry);
975 } else if (invoke_time > current_time) {
976 // register callback function since we now know when an io request will finish
977 mmi_register_event(_etable.get_invoke_time(entry), (EventFunc_T*)&sas_io_callback, (void *)this, (void *)entry);
978 } else {
979 // invoke time should not be less than current time
980 debug_err("%s: callback function invoke time %lld is less than current time %lld\n", getName(), invoke_time, current_time);
981 exit(1);
982 }
983
984 _request_queue_size--;
985 }
986 else {
987 *in_buf = _mpt_reg->req_q;
988 }
989}
990
991
992void SAS::access_reply_queue(bool wr, uint64_t *in_buf, uint8_t size) {
993 if (wr) {
994 uint32_t l_buf = *in_buf;
995 // each written value is regarded as reply free MFA from the host
996 // which will be pushed into reply free queue
997 _reply_free_queue.push(l_buf);
998 }
999 else {
1000 // without disk delay, reading reply queue and updating reply
1001 // queue are mutually exclusive (protected by lock in mpt driver).
1002 // if disk delay is simulated, this is no longer true, because
1003 // updating reply queue is done some time later after a request
1004 // is received, and it is no longer under the proctection of mpt driver.
1005 pthread_mutex_lock(&_reply_queue_mutex);
1006
1007 if (!_reply_post_queue.empty()) {
1008 assert(_mpt_reg->intr_status & MPI_HIS_REPLY_MESSAGE_INTERRUPT);
1009
1010 _mpt_reg->reply_q = _reply_post_queue.front();
1011 _reply_post_queue.pop();
1012
1013 if (_reply_post_queue.empty()) {
1014 // self-clear reply message interrupt if queue is empty
1015 _mpt_reg->intr_status &= ~MPI_HIS_REPLY_MESSAGE_INTERRUPT;
1016
1017 if (!msi_enabled()) {
1018 // don't deassert interrupt if doorbell interrupt is set
1019 if ((_mpt_reg->intr_status & MPI_HIS_DOORBELL_INTERRUPT) == 0) {
1020 debug_info("%s: deassert interrupt\n", getName());
1021 pcieCompleter status = busIf->busif_msgAccess((uint8_t)MSG_Deassert_INTA, local, getId(),&samId);
1022 if (handleCompletion(status) == -1) {
1023 debug_err("%s: pcie error when deasserting reply msg interrupt\n");
1024 exit(1);
1025 }
1026 }
1027 }
1028 }
1029 }
1030 else {
1031 // interrupt should have been cleared when the last message is read
1032 assert(!(_mpt_reg->intr_status & MPI_HIS_REPLY_MESSAGE_INTERRUPT));
1033
1034 // send 0xffffffff to the host indicating reply post queue is empty
1035 _mpt_reg->reply_q = 0xffffffff;
1036 _mpt_reg->intr_status &= ~MPI_HIS_REPLY_MESSAGE_INTERRUPT;
1037 }
1038
1039 pthread_mutex_unlock(&_reply_queue_mutex);
1040
1041 *in_buf = _mpt_reg->reply_q;
1042 }
1043}
1044
1045
1046void SAS::access_hi_pri_request_queue(bool wr, uint64_t *in_buf, uint8_t size) {
1047 if (wr) {
1048 _mpt_reg->pri_req_q = *in_buf;
1049 }
1050 else {
1051 *in_buf = _mpt_reg->pri_req_q;
1052 }
1053}
1054
1055
1056bool SAS::memory_space_access(int offset,bool wr, uint64_t *in_buf, uint8_t size) {
1057
1058 // must be a word
1059 assert(size == 4);
1060 assert(offset >= 0);
1061
1062 if (offset >= _io_base && offset < _io_base + IO_SIZE) {
1063 offset -= _io_base;
1064 }
1065 else if (offset >= _mem0_base && offset < _mem0_base + MEM0_SIZE) {
1066 offset -= _mem0_base;
1067 }
1068 else if (offset >= _mem1_base && offset < _mem1_base + MEM1_SIZE) {
1069 offset -= _mem1_base;
1070 }
1071 else {
1072 debug_err("%s: memory space 0x%llx is not allocated\n", getName(), offset);
1073 return false;
1074 }
1075
1076 switch (offset) {
1077 case MPI_DOORBELL_OFFSET:
1078 access_door_bell(wr, in_buf, size);
1079 break;
1080 case MPI_WRITE_SEQUENCE_OFFSET:
1081 access_write_sequence(wr, in_buf, size);
1082 break;
1083 case MPI_DIAGNOSTIC_OFFSET:
1084 access_host_diagnostic(wr, in_buf, size);
1085 break;
1086 case MPI_TEST_BASE_ADDRESS_OFFSET:
1087 access_test_base_address(wr, in_buf, size);
1088 break;
1089 case MPI_DIAG_RW_DATA_OFFSET:
1090 access_diag_rw_data(wr, in_buf, size);
1091 break;
1092 case MPI_DIAG_RW_ADDRESS_OFFSET:
1093 access_diag_rw_address(wr, in_buf, size);
1094 break;
1095 case MPI_HOST_INTERRUPT_STATUS_OFFSET:
1096 access_host_interrupt_status(wr, in_buf, size);
1097 break;
1098 case MPI_HOST_INTERRUPT_MASK_OFFSET:
1099 access_host_interrupt_mask(wr, in_buf, size);
1100 break;
1101 case MPI_REQUEST_QUEUE_OFFSET:
1102 access_host_request_queue(wr, in_buf, size);
1103 break;
1104 case MPI_REPLY_QUEUE_OFFSET:
1105 access_reply_queue(wr, in_buf, size);
1106 break;
1107 case MPI_HI_PRI_REQUEST_QUEUE_OFFSET:
1108 access_hi_pri_request_queue(wr, in_buf, size);
1109 break;
1110 default:
1111 debug_err("%s: memory space 0x%llx is reserved\n", getName(), offset);
1112 return false;
1113 }
1114
1115 return true;
1116}
1117
1118
1119pcieCompleter SAS::devif_memAccess(bool wr, uint64_t offset, addrMd_xactnType mode, void * data,\
1120 uint16_t length, uint8_t be, uint16_t reqId, tlp_X args,SAM_DeviceId *id) {
1121 bool ret;
1122 int size = byteEnabletoSize(be);
1123
1124 if(id) *id = samId;
1125
1126 if (wr) {
1127 *(uint64_t*)data &= 0xFFFFFFFF;
1128 uint32_t l_buf = *(uint64_t*)data;
1129 if(size == 4){
1130 *(uint64_t*)data = swap_word(l_buf);
1131 }else if(size == 2){
1132 *(uint64_t*)data = swap_hword(l_buf);
1133 }else if (size == 1)
1134 *(uint64_t*)data = l_buf;
1135 debug_info("%s: memory space: offset <0x%x> wr size<%d> be<0x%x> data<0x%llx>\n",
1136 getName(), offset, size, be, *(uint64_t*)data);
1137 }
1138
1139 ret = memory_space_access(offset, wr, (uint64_t *)data, size);
1140
1141 if (!wr) {
1142 uint32_t l_buf = *(uint64_t*)data;
1143 if(size == 4){
1144 *(uint64_t*)data = swap_word(l_buf & 0xFFFFFFFF);
1145 }else if(size == 2){
1146 *(uint64_t*)data = swap_hword(l_buf & 0xFFFF);
1147 }else if (size == 1)
1148 *(uint64_t*)data = l_buf & 0xFF;
1149
1150 debug_info("%s: memory space: offset <0x%x> rd size<%d> be<0x%x> data<0x%llx>\n",
1151 getName(), offset, size, be, *(uint64_t*)data);
1152 debug_info("\n");
1153 }
1154
1155 return (ret ? pcieCompleter(SC,getId()) : pcieCompleter(UR,getId()));
1156}
1157
1158
1159pcieCompleter SAS::devif_ioAccess(bool wr, uint32_t offset, void * data, uint8_t be, \
1160 uint16_t reqId, uint16_t length, tlp_X args,SAM_DeviceId* id) {
1161 debug_info("%s: io space 0x%llx is %s\n", getName(), offset, wr?"written":"read");
1162 if(id) *id = samId;
1163 return pcieCompleter();
1164}
1165
1166
1167pcieCompleter SAS::devif_msgAccess(uint8_t messageCode, msgRouting route, uint64_t tarIdOrAddr, uint16_t reqId, \
1168 void * data, uint16_t length, uint16_t vendorId, uint32_t vendor_data, tlp_X args,SAM_DeviceId * id) {
1169 debug_info("%s: message space is accessed\n", getName());
1170 if(id) *id = samId;
1171 return pcieCompleter();
1172}
1173
1174
1175const char *Module::get_help_string(){
1176 return SAS1064E_Help;
1177}
1178
1179
1180Module *Module::create(const char *_modname, const char *_instance_name){
1181 return new SAS(_modname, _instance_name);
1182}
1183
1184
1185bool SAS::dump(FILE *fp) {
1186 const char *dump_dir = DR_get_dir();
1187 const char *dev_name = getName();
1188 uint16_t qsize;
1189 uint32_t qvalue;
1190 int i;
1191
1192 assert(dump_dir);
1193
1194 // dump generic pcie device info into "dump_dir/dev_name.pcie"
1195 bool ret = genericPcieDev::dump(dump_dir, dev_name);
1196
1197 // dump all disk info are dumped into "dump_dir/sas_ctrl_dev_name/"
1198 char *dirname = (char *)malloc(strlen(dump_dir) + strlen(dev_name) + 15);
1199 sprintf(dirname, "%s/sas_ctrl_%s", dump_dir, dev_name);
1200
1201 if (mkdir(dirname, S_IRWXU | S_IRWXG | S_IRWXO) == -1) {
1202 debug_err("%s: can't create directory %s\n", getName(), dirname);
1203 }
1204
1205 for (i = 0; i < IOC_NUM_PORTS; i++)
1206 if (_disk[i])
1207 _disk[i]->dump(dirname);
1208
1209 // dump all controller info into "dump_dir/dev_name.dmp"
1210 // there are several categories, each categories starts with "#category_name number_of_fields"
1211
1212 // dump registers
1213 fprintf(fp, "#reg %d\n", 11);
1214 fprintf(fp, "reg_doorbell %u\n", _mpt_reg->doorbell);
1215 fprintf(fp, "reg_write_seq %u\n", _mpt_reg->write_seq);
1216 fprintf(fp, "reg_diag %u\n", _mpt_reg->diag);
1217 fprintf(fp, "reg_test_base_addr %u\n", _mpt_reg->test_base_addr);
1218 fprintf(fp, "reg_diagrw_data %u\n", _mpt_reg->diagrw_data);
1219 fprintf(fp, "reg_diagrw_addr %u\n", _mpt_reg->diagrw_addr);
1220 fprintf(fp, "reg_intr_status %u\n", _mpt_reg->intr_status);
1221 fprintf(fp, "reg_intr_mask %u\n", _mpt_reg->intr_mask);
1222 fprintf(fp, "reg_req_q %u\n", _mpt_reg->req_q);
1223 fprintf(fp, "reg_reply_q %u\n", _mpt_reg->reply_q);
1224 fprintf(fp, "reg_pri_req_q %u\n", _mpt_reg->pri_req_q);
1225
1226 // dump ioc configuration
1227 fprintf(fp, "#conf %d\n", 9);
1228 fprintf(fp, "conf_who_init %hhu\n", _ioc_conf->who_init);
1229 fprintf(fp, "conf_max_devices %hhu\n", _ioc_conf->max_devices);
1230 fprintf(fp, "conf_max_buses %hhu\n", _ioc_conf->max_buses);
1231 fprintf(fp, "conf_reply_frame_size %hu\n", _ioc_conf->reply_frame_size);
1232 fprintf(fp, "conf_host_mfa_high_addr %u\n", _ioc_conf->host_mfa_high_addr);
1233 fprintf(fp, "conf_sense_buffer_high_addr %u\n", _ioc_conf->sense_buffer_high_addr);
1234 fprintf(fp, "conf_host_page_buffer_sge_FlagsLength %u\n", _ioc_conf->host_page_buffer_sge.FlagsLength);
1235 fprintf(fp, "conf_host_page_buffer_sge_Address_Low %u\n", _ioc_conf->host_page_buffer_sge.Address_Low);
1236 fprintf(fp, "conf_host_page_buffer_sge_Address_High %u\n", _ioc_conf->host_page_buffer_sge.Address_High);
1237
1238 // dump eariliest serving time
1239 fprintf(fp, "#port_est %d\n", IOC_NUM_PORTS);
1240 for (i = 0; i < IOC_NUM_PORTS; i++)
1241 fprintf(fp, "port[%d] %lld\n", i, _earliest_serving_time[i]);
1242
1243 // dump port enabled
1244 fprintf(fp, "#port_enabled %d\n", IOC_NUM_PORTS);
1245 for (i = 0; i < IOC_NUM_PORTS; i++)
1246 fprintf(fp, "port[%d] %hhu\n", i, _port_enabled[i]);
1247
1248 // dump handshake request messages
1249 fprintf(fp, "#hdshk_msg_req %d\n", _hdshk_msg_req_size+2);
1250 fprintf(fp, "hdshk_msg_req_size %hhu\n", _hdshk_msg_req_size);
1251 fprintf(fp, "hdshk_msg_req_recv %hhu\n", _hdshk_msg_req_recv);
1252 for (i = 0; i < (_hdshk_msg_req_size << 2); i++)
1253 fprintf(fp, "hdshk_msg_req_buf[%d], %hhu\n", i, _hdshk_msg_req_buf[i]);
1254
1255 // dump handshake reply messages
1256 fprintf(fp, "#hdshk_msg_reply %d\n", _hdshk_msg_reply_size+2);
1257 fprintf(fp, "hdshk_msg_reply_size %hhu\n", _hdshk_msg_reply_size);
1258 fprintf(fp, "hdshk_msg_reply_send %hhu\n", _hdshk_msg_reply_send);
1259 for (i = 0; i < (_hdshk_msg_reply_size << 2); i++)
1260 fprintf(fp, "hdshk_msg_reply_buf[%d], %hhu\n", i, _hdshk_msg_reply_buf[i]);
1261
1262 // dump request queue
1263 fprintf(fp, "#request_queue %d\n", _request_queue_size);
1264
1265 // dump reply post queue
1266 qsize = _reply_post_queue.size();
1267 fprintf(fp, "#reply_post_queue %d\n", qsize);
1268 for (i = 0; i < qsize; i++) {
1269 qvalue = _reply_post_queue.front();
1270 fprintf(fp, "reply_post_queue[%d] %u\n", i, qvalue);
1271 _reply_post_queue.pop();
1272 _reply_post_queue.push(qvalue);
1273 }
1274
1275 // dump reply free queue
1276 qsize = _reply_free_queue.size();
1277 fprintf(fp, "#reply_free_queue %d\n", qsize);
1278 for (i = 0; i < qsize; i++) {
1279 qvalue = _reply_free_queue.front();
1280 fprintf(fp, "reply_free_queue[%d] %u\n", i, qvalue);
1281 _reply_free_queue.pop();
1282 _reply_free_queue.push(qvalue);
1283 }
1284
1285 // dump event table
1286 fprintf(fp, "#event_table %d\n", EVENT_TABLE_SIZE);
1287 _etable.dump(this, fp);
1288
1289 // copy disk configuration file into "dump_dir/sas_ctrl_dev_name/"
1290 char *cpcmd = (char *)malloc(strlen(fname) + strlen(dirname) + 10);
1291 sprintf(cpcmd, "cp %s %s", fname, dirname);
1292 if (system(cpcmd) != 0) {
1293 debug_err("%s: can't dump disk configuration file %s to %s\n", getName(), fname, dirname);
1294 exit(1);
1295 }
1296
1297 free(dirname);
1298 free(cpcmd);
1299
1300 return ret;
1301}
1302
1303
1304bool SAS::restore(FILE * fp) {
1305 const char *dump_dir = DR_get_dir();
1306 const char *dev_name = getName();
1307 char name[128], type[128];
1308 uint32_t items;
1309 uint32_t qvalue;
1310 int i, num_ports;
1311
1312 // restore generic pcie device information from "dump_dir/dev_name.pcie"
1313 assert(dump_dir);
1314 bool ret = genericPcieDev::restore(dump_dir, dev_name);
1315
1316 // restore disks from "dump_dir/sas_ctrl_dev_name/"
1317 char *dirname = (char *)malloc(strlen(dump_dir) + strlen(dev_name) + 15);
1318 sprintf(dirname, "%s/sas_ctrl_%s", dump_dir, dev_name);
1319
1320 for (i = 0; i < IOC_NUM_PORTS; i++)
1321 if (_disk[i])
1322 _disk[i]->restore(dirname);
1323
1324 // restore controller info from "dump_dir/dev_name.dmp".
1325 // Data structure may be changed, so does checkpoint.
1326 // We want to have compatibility among checkpoints,
1327 // so a fully associative search/comparison is needed
1328 // during restore. To make it efficient, info are organized
1329 // into categories, so that we can afford fully associative
1330 // search within each category, while each category itself
1331 // is identified also by fully associative search.
1332 // Some category may not need any search during restore.
1333
1334 while (fscanf(fp, "%s %d\n", &type, &items) != EOF) {
1335 if (strcmp(type, "#reg") == NULL) {
1336 // restore registers
1337 uint32_t reg_value;
1338 for (i = 0; i < items; i++) {
1339 fscanf(fp, "%s %u\n", name, &reg_value);
1340 if (strcmp(name, "reg_doorbell") == NULL)
1341 _mpt_reg->doorbell = reg_value;
1342 else if (strcmp(name, "reg_write_seq") == NULL)
1343 _mpt_reg->write_seq = reg_value;
1344 else if (strcmp(name, "reg_diag") == NULL)
1345 _mpt_reg->diag = reg_value;
1346 else if (strcmp(name, "reg_test_base_addr") == NULL)
1347 _mpt_reg->test_base_addr = reg_value;
1348 else if (strcmp(name, "reg_diagrw_data") == NULL)
1349 _mpt_reg->diagrw_data = reg_value;
1350 else if (strcmp(name, "reg_diagrw_addr") == NULL)
1351 _mpt_reg->diagrw_addr = reg_value;
1352 else if (strcmp(name, "reg_intr_status") == NULL)
1353 _mpt_reg->intr_status = reg_value;
1354 else if (strcmp(name, "reg_intr_mask") == NULL)
1355 _mpt_reg->intr_mask = reg_value;
1356 else if (strcmp(name, "reg_req_q") == NULL)
1357 _mpt_reg->req_q = reg_value;
1358 else if (strcmp(name, "reg_reply_q") == NULL)
1359 _mpt_reg->reply_q = reg_value;
1360 else if (strcmp(name, "reg_pri_req_q") == NULL)
1361 _mpt_reg->pri_req_q = reg_value;
1362 else
1363 debug_info("%s: unknown register %s\n", getName(), name);
1364 }
1365 }
1366 else if (strcmp(type, "#conf") == NULL) {
1367 // restore ioc configuration
1368 uint32_t conf_value;
1369 for (i = 0; i < items; i++) {
1370 fscanf(fp, "%s %u\n", name, &conf_value);
1371 if (strcmp(name, "conf_who_init") == NULL)
1372 _ioc_conf->who_init = conf_value;
1373 else if (strcmp(name, "conf_max_devices") == NULL)
1374 _ioc_conf->max_devices = conf_value;
1375 else if (strcmp(name, "conf_max_buses") == NULL)
1376 _ioc_conf->max_buses = conf_value;
1377 else if (strcmp(name, "conf_reply_frame_size") == NULL)
1378 _ioc_conf->reply_frame_size = conf_value;
1379 else if (strcmp(name, "conf_host_mfa_high_addr") == NULL)
1380 _ioc_conf->host_mfa_high_addr = conf_value;
1381 else if (strcmp(name, "conf_sense_buffer_high_addr") == NULL)
1382 _ioc_conf->sense_buffer_high_addr = conf_value;
1383 else if (strcmp(name, "conf_host_page_buffer_sge_FlagsLength") == NULL)
1384 _ioc_conf->host_page_buffer_sge.FlagsLength = conf_value;
1385 else if (strcmp(name, "conf_host_page_buffer_sge_Address_Low") == NULL)
1386 _ioc_conf->host_page_buffer_sge.Address_Low = conf_value;
1387 else if (strcmp(name, "conf_host_page_buffer_sge_Address_High") == NULL)
1388 _ioc_conf->host_page_buffer_sge.Address_High = conf_value;
1389 }
1390 }
1391 else if (strcmp(type, "#port_est") == NULL) {
1392 // restore eariliest serving time
1393 for (i = 0; i < items; i++)
1394 fscanf(fp, "%s %lld\n", name, &_earliest_serving_time[i]);
1395 }
1396 else if (strcmp(type, "#port_enabled") == NULL) {
1397 // restore port enabled
1398 for (i = 0; i < items; i++)
1399 fscanf(fp, "%s %hhu\n", name, &_port_enabled[i]);
1400 }
1401 else if (strcmp(type, "#hdshk_msg_req") == NULL) {
1402 // restore handshake request messages
1403 fscanf(fp, "%s %hhu\n", name, &_hdshk_msg_req_size);
1404 fscanf(fp, "%s %hhu\n", name, &_hdshk_msg_req_recv);
1405 for (i = 0; i < (_hdshk_msg_req_size << 2); i++)
1406 fscanf(fp, "%s %hhu\n", name, &_hdshk_msg_req_buf[i]);
1407 }
1408 else if (strcmp(type, "#hdshk_msg_reply") == NULL) {
1409 // restore handshake reply messages
1410 fscanf(fp, "%s %hhu\n", name, &_hdshk_msg_reply_size);
1411 fscanf(fp, "%s %hhu\n", name, &_hdshk_msg_reply_send);
1412 for (i = 0; i < (_hdshk_msg_reply_size << 2); i++)
1413 fscanf(fp, "%s %hhu\n", name, &_hdshk_msg_reply_buf[i]);
1414 }
1415 else if (strcmp(type, "#request_queue") == NULL) {
1416 // restore request queue
1417 _request_queue_size = items;
1418 }
1419 else if (strcmp(type, "#reply_post_queue") == NULL) {
1420 // restore reply post queue
1421 for (i = 0; i < items; i++) {
1422 fscanf(fp, "%s %u\n", name, &qvalue);
1423 _reply_post_queue.push(qvalue);
1424 }
1425 }
1426 else if (strcmp(type, "#reply_free_queue") == NULL) {
1427 // restore reply free queue
1428 for (i = 0; i < items; i++) {
1429 fscanf(fp, "%s %u\n", name, &qvalue);
1430 _reply_free_queue.push(qvalue);
1431 }
1432 }
1433 else if (strcmp(type, "#event_table") == NULL) {
1434 // restore event table
1435 _etable.restore(this, fp);
1436 }
1437 else
1438 debug_info("%s: unknown type %s\n", getName(), type);
1439 }
1440
1441 free(dirname);
1442
1443 return ret;
1444}