Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / sas / sas_mpi.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: sas_mpi.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_mpi.cc" LSI SAS1064E PCIE to 4-Port Serial Attached
23 * SCSI Controller Simulator
24 * Message Passing Interface (MPI) implementation
25 *
26 * Copyright (C) 2007 Sun Microsystems, Inc.
27 * All rights reserved.
28 *
29 */
30#include "sas.h"
31
32
33// length is (ceiling(size/8)*8)/4, i.e. 0~7=>0, 8=>2, 9=>4
34uint32_t get_length(uint32_t size) {
35 uint32_t length;
36
37 assert(size > 0);
38
39 length = size >> 3;
40 if (size % 8)
41 length++;
42
43 return(length << 1);
44}
45
46
47// be is used to represent each byte in the remainder (div by 8)
48uint8_t get_be(uint32_t size) {
49 uint32_t remain;
50 uint8_t be = 0;
51
52 assert(size > 0);
53
54 remain = size % 8;
55
56 if (remain == 0)
57 remain = 8;
58
59 for (int i = 0; i < remain; i++)
60 be |= (1 << i);
61
62 return(be);
63}
64
65
66// Transport data to/from simulated memory (pointed by "va")
67// from/to the host memory (pointed by "data").
68void SAS::memory_access(uint64_t va, addrMd_xactnType mode, void *data, uint32_t size, bool wr) {
69 uint32_t rem_size = size;
70 uint32_t t_size;
71
72 while (rem_size) {
73
74 // the size of data in each memory transfer is limited by the "length"
75 // parameter (roughly size/4) in busif_access(), which is 16-bit.
76 if (rem_size > 0x20000)
77 t_size = 0x20000;
78 else
79 t_size = rem_size;
80
81 pcieCompleter status = busIf->busif_access(PCIE_MEM, wr, va, data,
82 get_length(t_size), get_be(t_size), getId(), mode,&samId);
83 if (handleCompletion(status) == -1) {
84 debug_err("%s: pcie error when transferring data to/from memory\n");
85 exit(1);
86 }
87
88 rem_size -= t_size;
89 va += t_size;
90 data = (uchar_t *)data + t_size;
91 }
92}
93
94
95// Transport data to/from simulated memory (pointed by "sge_addr")
96// from/to the host memory (pointed by "data").
97// Note: sge_addr is the address of memory location where actually SGE is stored.
98// So we have to first read SGE using sge_addr, and this involves memory_access().
99// Then we have to move data to/from the memory location specified by SGE, which
100// also involves memory_access().
101void SAS::memory_transport(uint64_t sge_addr, addrMd_xactnType sge_addr_mode, void *data, uint32_t size, bool wr) {
102 uint32_t flaglength;
103
104 memory_access(sge_addr, sge_addr_mode, (void*)&flaglength, 4, false);
105 flaglength = SAM_LE_32(flaglength);
106
107 uint8_t flag = flaglength >> MPI_SGE_FLAGS_SHIFT;
108 uint64_t mem_addr;
109 addrMd_xactnType mem_addr_mode;
110 uint64_t next_sge_addr;
111 addrMd_xactnType next_sge_addr_mode;
112
113 if ((flag & MPI_SGE_FLAGS_ELEMENT_MASK) == MPI_SGE_FLAGS_SIMPLE_ELEMENT) {
114 uint32_t length = flaglength & MPI_SGE_LENGTH_MASK;
115
116 if (flag & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
117 // 64-bit addressing
118 mem_addr_mode = mem_addr64;
119
120 sge_simple64_t *simple_64 = (sge_simple64_t *)calloc(1, sizeof(sge_simple64_t));
121
122 memory_access(sge_addr, sge_addr_mode, (void*)simple_64, sizeof(sge_simple64_t), false);
123
124 simple_64->FlagsLength = SAM_LE_32(simple_64->FlagsLength);
125 simple_64->Address_Low = SAM_LE_32(simple_64->Address_Low);
126 simple_64->Address_High = SAM_LE_32(simple_64->Address_High);
127
128 mem_addr = (simple_64->Address_High << 32) | simple_64->Address_Low;
129 }
130 else {
131 // 32-bit addressing
132 mem_addr_mode = mem_addr32;
133
134 sge_simple32_t *simple_32 = (sge_simple32_t *)calloc(1, sizeof(sge_simple32_t));
135
136 memory_access(sge_addr, sge_addr_mode, (void*)simple_32, sizeof(sge_simple32_t), false);
137
138 simple_32->FlagsLength = SAM_LE_32(simple_32->FlagsLength);
139 simple_32->Address = SAM_LE_32(simple_32->Address);
140
141 mem_addr = simple_32->Address;
142 }
143
144 if (length < size) {
145 // more SGEs
146 memory_access(mem_addr, mem_addr_mode, data, length, wr);
147
148 next_sge_addr = sge_addr +
149 (mem_addr_mode == mem_addr32) ? sizeof(sge_simple32) : sizeof(sge_simple64);
150
151 memory_transport(next_sge_addr, sge_addr_mode, (void*)((uchar_t *)data + length), size - length, wr);
152
153 }
154 else {
155 // last SGE
156 memory_access(mem_addr, mem_addr_mode, data, size, wr);
157 }
158 }
159 else if ((flag & MPI_SGE_FLAGS_ELEMENT_MASK) == MPI_SGE_FLAGS_CHAIN_ELEMENT) {
160 if (flag & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
161 // 64-bit addressing
162 sge_chain64_t *chain_64 = (sge_chain64_t *)calloc(1, sizeof(sge_chain64_t));
163
164 memory_access(sge_addr, sge_addr_mode, (void*)chain_64, sizeof(sge_chain64_t), false);
165
166 chain_64->Length = SAM_LE_16(chain_64->Length);
167 chain_64->Address64_Low = SAM_LE_32(chain_64->Address64_Low);
168 chain_64->Address64_High = SAM_LE_32(chain_64->Address64_High);
169
170 next_sge_addr = (chain_64->Address64_High << 32) | chain_64->Address64_Low;
171 next_sge_addr_mode = mem_addr64;
172 }
173 else {
174 // 32-bit addressing
175 sge_chain32_t *chain_32 = (sge_chain32_t *)calloc(1, sizeof(sge_chain32_t));
176
177 memory_access(sge_addr, sge_addr_mode, (void*)chain_32, sizeof(sge_chain32_t), false);
178
179 chain_32->Length = SAM_LE_16(chain_32->Length);
180 chain_32->Address = SAM_LE_32(chain_32->Address);
181
182 next_sge_addr = chain_32->Address;
183 next_sge_addr_mode = mem_addr32;
184 }
185
186 memory_transport(next_sge_addr, next_sge_addr_mode, data, size, wr);
187 }
188 else {
189 debug_err("%s: only Simple and Chain Elements are supported\n", getName());
190 exit(1);
191 }
192}
193
194
195// Transport data to/from simulated memory (pointed by "sge")
196// from/to the host memory (pointed by "data").
197// Note: memory_transport() defined above will be called in the
198// case of chain element.
199void SAS::memory_transport(void *sge, void *data, uint32_t size, bool wr) {
200 uint32_t flaglength = *(uint32_t *)sge;
201
202 uint8_t flag = flaglength >> MPI_SGE_FLAGS_SHIFT;
203
204 uint64_t mem_addr;
205 addrMd_xactnType mem_addr_mode;
206 uint64_t next_sge_addr;
207 addrMd_xactnType next_sge_addr_mode;
208
209 if ((flag & MPI_SGE_FLAGS_ELEMENT_MASK) == MPI_SGE_FLAGS_SIMPLE_ELEMENT) {
210 uint32_t length = flaglength & MPI_SGE_LENGTH_MASK;
211
212 if (flag & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
213 // 64-bit addressing
214 mem_addr_mode = mem_addr64;
215
216 sge_simple64 *simple_64 = (sge_simple64 *)sge;
217
218 mem_addr = (simple_64->Address_High << 32) | simple_64->Address_Low;
219
220 }
221 else {
222 // 32-bit addressing
223 mem_addr_mode = mem_addr32;
224
225 sge_simple32 *simple_32 = (sge_simple32 *)sge;
226
227 mem_addr = simple_32->Address;
228 }
229
230 memory_access(mem_addr, mem_addr_mode, data, size, wr);
231 }
232 else if ((flag & MPI_SGE_FLAGS_ELEMENT_MASK) == MPI_SGE_FLAGS_CHAIN_ELEMENT) {
233 if (flag & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
234 // 64-bit addressing
235 sge_chain64 *chain_64 = (sge_chain64 *)sge;
236
237 next_sge_addr = (chain_64->Address64_High << 32) | chain_64->Address64_Low;
238 next_sge_addr_mode = mem_addr64;
239 }
240 else {
241 // 32-bit addressing
242 sge_chain32 *chain_32 = (sge_chain32 *)sge;
243
244 next_sge_addr = chain_32->Address;
245 next_sge_addr_mode = mem_addr32;
246 }
247
248 memory_transport(next_sge_addr, next_sge_addr_mode, data, size, wr);
249 }
250 else {
251 debug_err("%s: only Simple and Chain Elements are supported\n", getName());
252 exit(1);
253 }
254}
255
256
257// Send handshake reply msg to the host through doorbell
258// Note: the first hword is written to doorbell here,
259// and all remaining bytes are sent (hword at a time)
260// each time the doorbell is read.
261void SAS::send_handshake_msg() {
262 uint16_t value;
263
264 // set the size of message to be sent in hword
265 _hdshk_msg_reply_size = (((msg_default_reply *)_hdshk_msg_reply_buf)->MsgLength) << 1;
266 _hdshk_msg_reply_send = 0;
267
268 // put the first hword in the doorbell
269 value = SAM_LE_16(*(uint16_t *)(_hdshk_msg_reply_buf + (_hdshk_msg_reply_send << 1)));
270 _mpt_reg->doorbell = (_mpt_reg->doorbell & ~MPI_DOORBELL_DATA_MASK) | value;
271 _hdshk_msg_reply_send++;
272
273 // set interrupt
274 set_doorbell_interrupt();
275}
276
277
278// Process a handshake msg received through doorbell
279// Request msg is in little-endian, should be converted into big-endian after receiving
280// Reply msg is in big-endian, should be converted into little-endian before sending
281void SAS::process_handshake_msg() {
282 msg_request_header_t *msg = (msg_request_header_t *)_hdshk_msg_req_buf;
283
284 switch (msg->Function) {
285 case MPI_FUNCTION_CONFIG: {
286 debug_info("%s: MPI_FUNCTION_CONFIG\n", getName());
287
288 msg_config_t *config_req;
289 msg_config_reply_t *config_reply;
290
291 config_req = (msg_config_t *)_hdshk_msg_req_buf;
292 config_reply = (msg_config_reply_t *)_hdshk_msg_reply_buf;
293 bzero(_hdshk_msg_reply_buf, HDSHK_MSG_SIZE);
294
295 config_req->ExtPageLength = SAM_LE_16(config_req->ExtPageLength);
296 config_req->MsgContext = SAM_LE_32(config_req->MsgContext);
297 config_req->PageAddress = SAM_LE_32(config_req->PageAddress);
298
299 // 1. PageBufferSGE is not 32-bit as described in MPT Ch.5
300 // 2. I am not sure it should be 64-bit or 128-bit, I prefer 128-bit as used by ioc_init and ioc_facts
301 // 3. However, 64-bit is used here according to the driver code in OBP and Solaris
302 // 4. swap() is based on sge_simple_union_t, it should be diferent if it is sge_chain_union_t
303 config_req->PageBufferSGE.u1.Simple.FlagsLength =
304 SAM_LE_32(config_req->PageBufferSGE.u1.Simple.FlagsLength);
305 config_req->PageBufferSGE.u1.Simple.u1.Address32=
306 SAM_LE_32(config_req->PageBufferSGE.u1.Simple.u1.Address32);
307
308 switch (config_req->Header.PageType & MPI_CONFIG_PAGETYPE_MASK) {
309 case MPI_CONFIG_PAGETYPE_IO_UNIT:
310 debug_err("%s: MPI_CONFIG_PAGETYPE_IO_UNIT not supported\n", getName());
311 exit(1);
312
313 case MPI_CONFIG_PAGETYPE_IOC:
314 access_page_ioc(config_req, config_reply);
315 break;
316
317 case MPI_CONFIG_PAGETYPE_BIOS:
318 debug_err("%s: MPI_CONFIG_PAGETYPE_IOC not supported\n", getName());
319 exit(1);
320
321 case MPI_CONFIG_PAGETYPE_SCSI_PORT:
322 debug_err("%s: MPI_CONFIG_PAGETYPE_SCSI_PORT not supported\n", getName());
323 exit(1);
324
325 case MPI_CONFIG_PAGETYPE_SCSI_DEVICE:
326 debug_err("%s: MPI_CONFIG_PAGETYPE_SCSI_DEVICE not supported\n", getName());
327 exit(1);
328
329 case MPI_CONFIG_PAGETYPE_FC_PORT:
330 debug_err("%s: MPI_CONFIG_PAGETYPE_FC_PORT not supported\n", getName());
331 exit(1);
332
333 case MPI_CONFIG_PAGETYPE_FC_DEVICE:
334 debug_err("%s: PI_CONFIG_PAGETYPE_FC_DEVICE not supported\n", getName());
335 exit(1);
336
337 case MPI_CONFIG_PAGETYPE_LAN:
338 debug_err("%s: MPI_CONFIG_PAGETYPE_LAN not supported\n", getName());
339 exit(1);
340
341 case MPI_CONFIG_PAGETYPE_RAID_VOLUME:
342 debug_err("%s: MPI_CONFIG_PAGETYPE_RAID_VOLUME not supported\n", getName());
343 exit(1);
344
345 case MPI_CONFIG_PAGETYPE_MANUFACTURING:
346 access_page_manufacturing(config_req, config_reply);
347 break;
348
349 case MPI_CONFIG_PAGETYPE_RAID_PHYSDISK:
350 debug_err("%s: MPI_CONFIG_PAGETYPE_RAID_PHYSDISK not supported\n", getName());
351 exit(1);
352
353 case MPI_CONFIG_PAGETYPE_INBAND:
354 debug_err("%s: MPI_CONFIG_PAGETYPE_INBAND not supported\n", getName());
355 exit(1);
356
357 case MPI_CONFIG_PAGETYPE_EXTENDED:
358 switch (config_req->ExtPageType) {
359 case MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT:
360 access_page_sas_io_unit(config_req, config_reply);
361 break;
362
363 case MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER:
364 debug_err("%s: MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER not impl\n", getName());
365 exit(1);
366
367 case MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE:
368 access_page_sas_device(config_req, config_reply);
369 break;
370
371 case MPI_CONFIG_EXTPAGETYPE_SAS_PHY:
372 access_page_sas_phy(config_req, config_reply);
373 break;
374
375 default:
376 debug_err("%s: unknow page type\n", getName());
377 exit(1);
378 }
379
380 break;
381
382 default:
383 debug_err("%s: unknow page type\n", getName());
384 exit(1);
385 }
386
387 break;
388 }
389
390 case MPI_FUNCTION_EVENT_NOTIFICATION: {
391 debug_info("%s: MPI_FUNCTION_EVENT_NOTIFICATION\n", getName());
392
393 msg_event_notify_t *event_notify_req;
394 msg_event_notify_reply_t *event_notify_reply;
395
396 event_notify_req = (msg_event_notify_t *)_hdshk_msg_req_buf;
397 event_notify_reply = (msg_event_notify_reply_t *)_hdshk_msg_reply_buf;
398 bzero(_hdshk_msg_reply_buf, HDSHK_MSG_SIZE);
399
400 event_notify_reply->EventDataLength = 1;
401 event_notify_reply->MsgLength = sizeof(msg_event_notify_reply_t) >> 2;
402 event_notify_reply->Function = event_notify_req->Function;
403 event_notify_reply->AckRequired = 0;
404 event_notify_reply->MsgFlags = 0;
405 event_notify_reply->MsgContext = event_notify_req->MsgContext;
406 event_notify_reply->IOCStatus = SAM_LE_16(MPI_IOCSTATUS_SUCCESS);
407 event_notify_reply->IOCLogInfo = 0;
408 event_notify_reply->Event = SAM_LE_16(MPI_EVENT_EVENT_CHANGE);
409 event_notify_reply->EventContext = 0;
410 event_notify_reply->Data[0] = 0;
411
412 send_handshake_msg();
413
414 break;
415 }
416
417 case MPI_FUNCTION_FW_DOWNLOAD:
418 debug_err("%s: MPI_FUNCTION_FW_DOWNLOAD not impl\n", getName());
419 exit(1);
420
421 case MPI_FUNCTION_FW_UPLOAD:
422 debug_err("%s: MPI_FUNCTION_FW_UPLOAD not impl\n", getName());
423 exit(1);
424
425 case MPI_FUNCTION_IOC_FACTS: {
426 debug_info("%s: MPI_FUNCTION_IOC_FACTS\n", getName());
427
428 msg_ioc_facts_t *ioc_facts_req;
429 msg_ioc_facts_reply_t *ioc_facts_reply;
430
431 ioc_facts_req = (msg_ioc_facts_t *)_hdshk_msg_req_buf;
432 ioc_facts_reply = (msg_ioc_facts_reply_t *)_hdshk_msg_reply_buf;
433 bzero(_hdshk_msg_reply_buf, HDSHK_MSG_SIZE);
434
435 // read from ioc configuration
436 ioc_facts_reply->WhoInit = _ioc_conf->who_init;
437 ioc_facts_reply->MaxDevices = _ioc_conf->max_devices;
438 ioc_facts_reply->MaxBuses = _ioc_conf->max_buses;
439 ioc_facts_reply->CurrentHostMfaHighAddr = SAM_LE_32(_ioc_conf->host_mfa_high_addr);
440 ioc_facts_reply->CurrentSenseBufferHighAddr = SAM_LE_32(_ioc_conf->sense_buffer_high_addr);
441 ioc_facts_reply->CurReplyFrameSize = SAM_LE_16(_ioc_conf->reply_frame_size);
442 bcopy(&_ioc_conf->host_page_buffer_sge, &ioc_facts_reply->HostPageBufferSGE, sizeof(sge_simple64_t));
443 ioc_facts_reply->HostPageBufferSGE.FlagsLength = SAM_LE_32(ioc_facts_reply->HostPageBufferSGE.FlagsLength);
444 ioc_facts_reply->HostPageBufferSGE.Address_Low = SAM_LE_32(ioc_facts_reply->HostPageBufferSGE.Address_Low);
445 ioc_facts_reply->HostPageBufferSGE.Address_High = SAM_LE_32(ioc_facts_reply->HostPageBufferSGE.Address_High);
446
447 // others
448 ioc_facts_reply->MsgVersion = SAM_LE_16(MPI_VERSION);
449 ioc_facts_reply->HeaderVersion = SAM_LE_16(MPI_HEADER_VERSION);
450 ioc_facts_reply->MsgLength = sizeof(msg_ioc_facts_reply_t) >> 2;
451 ioc_facts_reply->Function = ioc_facts_req->Function;
452 ioc_facts_reply->IOCNumber = function;
453 ioc_facts_reply->MsgFlags = 0;
454 ioc_facts_reply->MsgContext = ioc_facts_req->MsgContext;
455 ioc_facts_reply->IOCExceptions = 0;
456 ioc_facts_reply->IOCStatus = SAM_LE_16(MPI_IOCSTATUS_SUCCESS);
457 ioc_facts_reply->IOCLogInfo = 0;
458 ioc_facts_reply->MaxChainDepth = IOC_CHAIN_DEPTH;
459 ioc_facts_reply->BlockSize = IOC_BLOCK_SIZE;
460 ioc_facts_reply->Flags = 4;
461 ioc_facts_reply->ReplyQueueDepth = SAM_LE_16(IOC_REPLY_QUEUE_DEPTH);
462 ioc_facts_reply->RequestFrameSize = SAM_LE_16(IOC_REQ_FRAME_SIZE);
463 ioc_facts_reply->ProductID = SAM_LE_16(IOC_PRODUCTION_ID);
464 ioc_facts_reply->GlobalCredits = SAM_LE_16(IOC_REQ_QUEUE_DEPTH);
465 ioc_facts_reply->NumberOfPorts = IOC_NUM_PORTS;
466 ioc_facts_reply->EventState = 0;
467 ioc_facts_reply->FWImageSize = 0;
468 ioc_facts_reply->IOCCapabilities = SAM_LE_32(IOC_CAPABILITIES);
469 ioc_facts_reply->FWVersion.Word = SAM_LE_32((MPI_VERSION << 16) | MPI_HEADER_VERSION);
470 ioc_facts_reply->HighPriorityQueueDepth = SAM_LE_16(IOC_PRI_QUEUE_DEPTH);
471
472 send_handshake_msg();
473
474 break;
475 }
476
477 case MPI_FUNCTION_IOC_INIT: {
478 debug_info("%s: MPI_FUNCTION_IOC_INIT\n", getName());
479
480 msg_ioc_init_t *ioc_init_req;
481 msg_ioc_init_reply_t *ioc_init_reply;
482
483 ioc_init_req = (msg_ioc_init_t *)_hdshk_msg_req_buf;
484 ioc_init_reply = (msg_ioc_init_reply_t *)_hdshk_msg_reply_buf;
485 bzero(_hdshk_msg_reply_buf, HDSHK_MSG_SIZE);
486
487 _ioc_conf->who_init = ioc_init_req->WhoInit;
488 _ioc_conf->max_devices = ioc_init_req->MaxDevices;
489 _ioc_conf->max_buses = ioc_init_req->MaxBuses;
490 _ioc_conf->reply_frame_size = SAM_LE_16(ioc_init_req->ReplyFrameSize);
491 _ioc_conf->host_mfa_high_addr = SAM_LE_32(ioc_init_req->HostMfaHighAddr);
492 _ioc_conf->sense_buffer_high_addr = SAM_LE_32(ioc_init_req->SenseBufferHighAddr);
493 _ioc_conf->host_page_buffer_sge.FlagsLength = SAM_LE_32(ioc_init_req->HostPageBufferSGE.FlagsLength);
494 _ioc_conf->host_page_buffer_sge.Address_Low = SAM_LE_32(ioc_init_req->HostPageBufferSGE.Address_Low);
495 _ioc_conf->host_page_buffer_sge.Address_High = SAM_LE_32(ioc_init_req->HostPageBufferSGE.Address_High);
496
497 // change the status to Operational
498 _mpt_reg->doorbell = (_mpt_reg->doorbell & ~MPI_IOC_STATE_MASK) | MPI_IOC_STATE_OPERATIONAL;
499
500 // read from ioc configuration
501 ioc_init_reply->WhoInit = _ioc_conf->who_init;
502 ioc_init_reply->MaxDevices = _ioc_conf->max_devices;
503 ioc_init_reply->MaxBuses = _ioc_conf->max_buses;
504
505 // others
506 ioc_init_reply->MsgLength = sizeof(msg_ioc_init_reply_t) >> 2;
507 ioc_init_reply->Function = ioc_init_req->Function;
508 ioc_init_reply->Flags = 4;
509 ioc_init_reply->MsgFlags = 0;
510 ioc_init_reply->MsgContext = ioc_init_req->MsgContext;
511 ioc_init_reply->IOCStatus = SAM_LE_16(MPI_IOCSTATUS_SUCCESS);
512 ioc_init_reply->IOCLogInfo = 0;
513
514 send_handshake_msg();
515
516 break;
517 }
518
519 case MPI_FUNCTION_PORT_ENABLE: {
520 debug_info("%s: MPI_FUNCTION_PORT_ENABLE\n", getName());
521
522 msg_port_enable_t *port_enable_req;
523 msg_port_enable_reply_t *port_enable_reply;
524
525 port_enable_req = (msg_port_enable_t *)_hdshk_msg_req_buf;
526 port_enable_reply = (msg_port_enable_reply_t *)_hdshk_msg_reply_buf;
527 bzero(_hdshk_msg_reply_buf, HDSHK_MSG_SIZE);
528
529 _port_enabled[port_enable_req->PortNumber] = 1;
530
531 port_enable_reply->MsgLength = sizeof(msg_port_enable_reply_t) >> 2;
532 port_enable_reply->Function = port_enable_req->Function;
533 port_enable_reply->PortNumber = port_enable_req->PortNumber;
534 port_enable_reply->MsgFlags = 0;
535 port_enable_reply->MsgContext = port_enable_req->MsgContext;
536 port_enable_reply->IOCStatus = SAM_LE_16(MPI_IOCSTATUS_SUCCESS);
537 port_enable_reply->IOCLogInfo = 0;
538
539 send_handshake_msg();
540
541 break;
542 }
543
544 case MPI_FUNCTION_PORT_FACTS: {
545 debug_info("%s: MPI_FUNCTION_PORT_FACTS\n", getName());
546
547 msg_port_facts_t *port_facts_req;
548 msg_port_facts_reply_t *port_facts_reply;
549
550 port_facts_req = (msg_port_facts_t *)_hdshk_msg_req_buf;
551 port_facts_reply = (msg_port_facts_reply_t *)_hdshk_msg_reply_buf;
552 bzero(_hdshk_msg_reply_buf, HDSHK_MSG_SIZE);
553
554 port_facts_reply->MsgLength = sizeof(msg_port_facts_reply_t) >> 2;
555 port_facts_reply->Function = port_facts_req->Function;
556 port_facts_reply->PortNumber = port_facts_req->PortNumber;
557 port_facts_reply->MsgFlags = 0;
558 port_facts_reply->MsgContext = port_facts_req->MsgContext;
559 port_facts_reply->IOCStatus = SAM_LE_16(MPI_IOCSTATUS_SUCCESS);
560 port_facts_reply->IOCLogInfo = 0;
561 port_facts_reply->PortType = PORT_TYPE;
562 port_facts_reply->MaxDevices = SAM_LE_16(PORT_MAX_DEVICES);
563 port_facts_reply->PortSCSIID = SAM_LE_16(PORT_SCSI_ID);
564 port_facts_reply->ProtocolFlags = SAM_LE_16(PORT_PROTOCOL_FLAGS);
565 port_facts_reply->MaxPostedCmdBuffers = SAM_LE_16(PORT_MAX_POSTED_CMD_BUFFERS);
566 port_facts_reply->MaxPersistentIDs = SAM_LE_16(PORT_MAX_PERSISTENT_IDS);
567 port_facts_reply->MaxLanBuckets = SAM_LE_16(PORT_MAX_LAN_BUCKETS);
568
569 send_handshake_msg();
570
571 break;
572 }
573
574 case MPI_FUNCTION_SCSI_TASK_MGMT: {
575 msg_scsi_task_mgmt_t *scsi_task_mgmt_req;
576 msg_scsi_task_mgmt_reply *scsi_task_mgmt_reply;
577
578 scsi_task_mgmt_req = (msg_scsi_task_mgmt_t *)_hdshk_msg_req_buf;
579 scsi_task_mgmt_reply = (msg_scsi_task_mgmt_reply *)_hdshk_msg_reply_buf;
580 bzero(_hdshk_msg_reply_buf, HDSHK_MSG_SIZE);
581
582 scsi_task_mgmt_reply->TargetID = scsi_task_mgmt_req->TargetID;
583 scsi_task_mgmt_reply->Bus = scsi_task_mgmt_req->Bus;
584 scsi_task_mgmt_reply->MsgLength = sizeof(msg_scsi_task_mgmt_reply) >> 2;
585 scsi_task_mgmt_reply->Function = scsi_task_mgmt_req->Function;
586 scsi_task_mgmt_reply->TaskType = scsi_task_mgmt_req->TaskType;
587 scsi_task_mgmt_reply->MsgFlags = 0;
588 scsi_task_mgmt_reply->MsgContext = scsi_task_mgmt_req->MsgContext;
589 scsi_task_mgmt_reply->IOCStatus = SAM_LE_16(MPI_IOCSTATUS_SUCCESS);
590 scsi_task_mgmt_reply->IOCLogInfo = 0;
591 scsi_task_mgmt_reply->TerminationCount = 0;
592
593 debug_info("%s: MPI_FUNCTION_SCSI_TASK_MGMT, type = %d\n", getName(), scsi_task_mgmt_reply->TaskType);
594
595 if (_reply_free_queue.empty()) {
596 debug_err("%s: reply free queue is empty\n", getName());
597 exit(1);
598 }
599
600 uint32_t fma = _reply_free_queue.front();
601 uint32_t msg_addr = fma & FMA_ADDRESS_MASK;
602 _reply_free_queue.pop();
603
604 memory_access(mfa_addr(msg_addr), mfa_addr_mode(), (void *)scsi_task_mgmt_reply, sizeof(msg_scsi_task_mgmt_reply), true);
605 send_mpi_msg(msg_addr >> 1, false, 0);
606
607 break;
608 }
609
610 case MPI_FUNCTION_TARGET_ASSIST:
611 debug_err("%s: MPI_FUNCTION_TARGET_ASSIST not impl\n", getName());
612 exit(1);
613
614 case MPI_FUNCTION_TARGET_STATUS_SEND:
615 debug_err("%s: MPI_FUNCTION_TARGET_STATUS_SEND not impl\n", getName());
616 exit(1);
617
618 default:
619 debug_err("%s: unsupported handshake message\n", getName());
620 exit(1);
621 }
622}
623
624
625// Send mpi context/address reply msg to the host
626void SAS::send_mpi_msg(uint32_t reply, bool is_cntx, uint8_t cntx_type) {
627 uint32_t fma = 0;
628
629 if (is_cntx) {
630 // context reply
631 fma |= (reply & MPI_CONTEXT_REPLY_CONTEXT_MASK);
632 fma |= ((cntx_type & 0x3) << MPI_CONTEXT_REPLY_TYPE_SHIFT);
633 }
634 else {
635 // address reply
636 fma |= (reply & MPI_ADDRESS_REPLY_ADDRESS_MASK);
637 fma |= MPI_CONTEXT_REPLY_A_BIT;
638 }
639
640 // both updating queue and sending interrupt should be protected by mutex
641 pthread_mutex_lock(&_reply_queue_mutex);
642
643 // push fma into reply post queue
644 _reply_post_queue.push(fma);
645
646 // set interrupt
647 set_reply_msg_interrupt();
648
649 pthread_mutex_unlock(&_reply_queue_mutex);
650}
651
652
653// Process a mpi message received through request queue
654// Request msg is in little-endian, should be converted into big-endian after receiving
655// Reply msg is in big-endian, should be converted into little-endian before sending
656void SAS::process_mpi_msg(int entry, uint32_t fma) {
657 uint8_t *msg_buf = (uint8_t *)calloc(256, sizeof(uint8_t));
658 uint32_t msg_addr = fma & FMA_ADDRESS_MASK;
659 uint64_t sge_addr = msg_addr + sizeof(msg_scsi_io_request_t) - sizeof(sge_io_union_t);
660
661 msg_request_header_t *msg_header;
662 msg_scsi_io_request_t *msg_scsi_io_req;
663
664 // read the header first
665 memory_access(mfa_addr(msg_addr), mfa_addr_mode(), (void *)msg_buf, sizeof(msg_request_header_t), false);
666 msg_header = (msg_request_header *)msg_buf;
667
668 // read and process scsi command according to different headers
669 switch (msg_header->Function) {
670 case MPI_FUNCTION_SCSI_IO_REQUEST: {
671 memory_access(mfa_addr(msg_addr), mfa_addr_mode(), (void *)msg_buf, sizeof(msg_scsi_io_request_t), false);
672 msg_scsi_io_req = (msg_scsi_io_request_t *)msg_buf;
673
674 msg_scsi_io_req->MsgContext = SAM_LE_32(msg_scsi_io_req->MsgContext);
675 msg_scsi_io_req->Control = SAM_LE_32(msg_scsi_io_req->Control);
676 msg_scsi_io_req->DataLength = SAM_LE_32(msg_scsi_io_req->DataLength);
677 msg_scsi_io_req->SenseBufferLowAddr = SAM_LE_32(msg_scsi_io_req->SenseBufferLowAddr);
678 msg_scsi_io_req->SGL.u1.Simple.FlagsLength =
679 SAM_LE_32(msg_scsi_io_req->SGL.u1.Simple.FlagsLength);
680 msg_scsi_io_req->SGL.u1.Simple.u1.Address32=
681 SAM_LE_32(msg_scsi_io_req->SGL.u1.Simple.u1.Address32);
682
683 process_scsi_cmd(entry, msg_scsi_io_req, sge_addr);
684
685 break;
686 }
687
688 default:
689 debug_err("%s: MPI message unsupported\n", getName());
690 exit(1);
691 }
692
693 free(msg_buf);
694}