mpi.c revision 285809
1/*******************************************************************************
2**
3*Copyright (c) 2014 PMC-Sierra, Inc.  All rights reserved.
4*
5*Redistribution and use in source and binary forms, with or without modification, are permitted provided
6*that the following conditions are met:
7*1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8*following disclaimer.
9*2. Redistributions in binary form must reproduce the above copyright notice,
10*this list of conditions and the following disclaimer in the documentation and/or other materials provided
11*with the distribution.
12*
13*THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
14*WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
15*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16*FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17*NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
18*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
20*SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
21
22********************************************************************************/
23
24/*******************************************************************************/
25/*! \file mpi.c
26 *  \brief The file is a MPI Libraries to implement the MPI functions
27 *
28 * The file implements the MPI Library functions.
29 *
30 */
31/*******************************************************************************/
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34#include <dev/pms/config.h>
35
36#include <dev/pms/RefTisa/sallsdk/spc/saglobal.h>
37
38#ifdef SA_ENABLE_TRACE_FUNCTIONS
39#ifdef siTraceFileID
40#undef siTraceFileID
41#endif
42#define siTraceFileID 'A'
43#endif
44
45#ifdef LOOPBACK_MPI
46extern int loopback;
47#endif
48/*******************************************************************************/
49
50/*******************************************************************************/
51/*******************************************************************************/
52/* FUNCTIONS                                                                   */
53/*******************************************************************************/
54/*******************************************************************************/
55/** \fn void mpiRequirementsGet(mpiConfig_t* config, mpiMemReq_t* memoryRequirement)
56 *  \brief Retrieves the MPI layer resource requirements
57 *  \param config            MPI configuration for the Host MPI Message Unit
58 *  \param memoryRequirement Returned data structure as defined by mpiMemReq_t
59 *                           that holds the different chunks of memory that are required
60 *
61 * The mpiRequirementsGet() function is used to determine the resource requirements
62 * for the SPC device interface
63 *
64 * Return: None
65 */
66/*******************************************************************************/
67void mpiRequirementsGet(mpiConfig_t* config, mpiMemReq_t* memoryRequirement)
68{
69  bit32 qIdx, numq;
70  mpiMemReq_t* memoryMap;
71  SA_DBG2(("Entering function:mpiRequirementsGet\n"));
72  SA_ASSERT((NULL != config), "config argument cannot be null");
73
74  memoryMap = memoryRequirement;
75  memoryMap->count = 0;
76
77  /* MPI Memory region 0 for MSGU(AAP1) Event Log for fw */
78  memoryMap->region[memoryMap->count].numElements = 1;
79  memoryMap->region[memoryMap->count].elementSize = sizeof(bit8) * config->mainConfig.eventLogSize;
80  memoryMap->region[memoryMap->count].totalLength = sizeof(bit8) * config->mainConfig.eventLogSize;
81  memoryMap->region[memoryMap->count].alignment = 32;
82  memoryMap->region[memoryMap->count].type = AGSA_DMA_MEM;
83  SA_DBG2(("mpiRequirementsGet:eventLogSize region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength ));
84  memoryMap->count++;
85
86  SA_DBG2(("mpiRequirementsGet:eventLogSize region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength ));
87  /* MPI Memory region 1 for IOP Event Log for fw */
88  memoryMap->region[memoryMap->count].numElements = 1;
89  memoryMap->region[memoryMap->count].elementSize = sizeof(bit8) * config->mainConfig.IOPeventLogSize;
90  memoryMap->region[memoryMap->count].totalLength = sizeof(bit8) * config->mainConfig.IOPeventLogSize;
91  memoryMap->region[memoryMap->count].alignment = 32;
92  memoryMap->region[memoryMap->count].type = AGSA_DMA_MEM;
93  SA_DBG2(("mpiRequirementsGet:IOPeventLogSize region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength ));
94  memoryMap->count++;
95
96  /* MPI Memory region 2 for consumer Index of inbound queues */
97  memoryMap->region[memoryMap->count].numElements = 1;
98  memoryMap->region[memoryMap->count].elementSize = sizeof(bit32) * config->numInboundQueues;
99  memoryMap->region[memoryMap->count].totalLength = sizeof(bit32) * config->numInboundQueues;
100  memoryMap->region[memoryMap->count].alignment = 4;
101  memoryMap->region[memoryMap->count].type = AGSA_DMA_MEM;
102  SA_DBG2(("mpiRequirementsGet:numInboundQueues region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength ));
103  memoryMap->count++;
104
105  /* MPI Memory region 3 for producer Index of outbound queues */
106  memoryMap->region[memoryMap->count].numElements = 1;
107  memoryMap->region[memoryMap->count].elementSize = sizeof(bit32) * config->numOutboundQueues;
108  memoryMap->region[memoryMap->count].totalLength = sizeof(bit32) * config->numOutboundQueues;
109  memoryMap->region[memoryMap->count].alignment = 4;
110  memoryMap->region[memoryMap->count].type = AGSA_DMA_MEM;
111  SA_DBG2(("mpiRequirementsGet:numOutboundQueues region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength ));
112  memoryMap->count++;
113
114  /* MPI Memory regions 4, ... for the inbound queues - depends on configuration */
115  numq = 0;
116  for(qIdx = 0; qIdx < config->numInboundQueues; qIdx++)
117  {
118    if(0 != config->inboundQueues[qIdx].numElements)
119    {
120        bit32 memSize = config->inboundQueues[qIdx].numElements * config->inboundQueues[qIdx].elementSize;
121        bit32 remainder = memSize & 127;
122
123        /* Calculate the size of this queue padded to 128 bytes */
124        if (remainder > 0)
125        {
126            memSize += (128 - remainder);
127        }
128
129        if (numq == 0)
130        {
131            memoryMap->region[memoryMap->count].numElements = 1;
132            memoryMap->region[memoryMap->count].elementSize = memSize;
133            memoryMap->region[memoryMap->count].totalLength = memSize;
134            memoryMap->region[memoryMap->count].alignment = 128;
135            memoryMap->region[memoryMap->count].type = AGSA_CACHED_DMA_MEM;
136        }
137        else
138        {
139            memoryMap->region[memoryMap->count].elementSize += memSize;
140            memoryMap->region[memoryMap->count].totalLength += memSize;
141        }
142
143        numq++;
144
145        if ((0 == ((qIdx + 1) % MAX_QUEUE_EACH_MEM)) ||
146            (qIdx == (bit32)(config->numInboundQueues - 1)))
147        {
148            SA_DBG2(("mpiRequirementsGet: (inboundQueues) memoryMap->region[%d].elementSize = %d\n",
149                     memoryMap->count, memoryMap->region[memoryMap->count].elementSize));
150            SA_DBG2(("mpiRequirementsGet: (inboundQueues) memoryMap->region[%d].numElements = %d\n",
151                     memoryMap->count, memoryMap->region[memoryMap->count].numElements));
152
153            memoryMap->count++;
154            numq = 0;
155        }
156    }
157  }
158
159  /* MPI Memory regions for the outbound queues - depends on configuration */
160  numq = 0;
161  for(qIdx = 0; qIdx < config->numOutboundQueues; qIdx++)
162  {
163    if(0 != config->outboundQueues[qIdx].numElements)
164    {
165        bit32 memSize = config->outboundQueues[qIdx].numElements * config->outboundQueues[qIdx].elementSize;
166        bit32 remainder = memSize & 127;
167
168        /* Calculate the size of this queue padded to 128 bytes */
169        if (remainder > 0)
170        {
171            memSize += (128 - remainder);
172        }
173
174        if (numq == 0)
175        {
176            memoryMap->region[memoryMap->count].numElements = 1;
177            memoryMap->region[memoryMap->count].elementSize = memSize;
178            memoryMap->region[memoryMap->count].totalLength = memSize;
179            memoryMap->region[memoryMap->count].alignment = 128;
180            memoryMap->region[memoryMap->count].type = AGSA_CACHED_DMA_MEM;
181        }
182        else
183        {
184            memoryMap->region[memoryMap->count].elementSize += memSize;
185            memoryMap->region[memoryMap->count].totalLength += memSize;
186        }
187
188        numq++;
189
190        if ((0 == ((qIdx + 1) % MAX_QUEUE_EACH_MEM)) ||
191            (qIdx ==  (bit32)(config->numOutboundQueues - 1)))
192        {
193            SA_DBG2(("mpiRequirementsGet: (outboundQueues) memoryMap->region[%d].elementSize = %d\n",
194                     memoryMap->count, memoryMap->region[memoryMap->count].elementSize));
195            SA_DBG2(("mpiRequirementsGet: (outboundQueues) memoryMap->region[%d].numElements = %d\n",
196                     memoryMap->count, memoryMap->region[memoryMap->count].numElements));
197
198
199            memoryMap->count++;
200            numq = 0;
201        }
202    }
203  }
204
205}
206
207/*******************************************************************************/
208/** \fn mpiMsgFreeGet(mpiICQueue_t *circularQ, bit16 messageSize, void** messagePtr)
209 *  \brief Retrieves a free message buffer from an inbound queue
210 *  \param circularQ    Pointer to an inbound circular queue
211 *  \param messageSize  Requested message size in bytes - only support 64 bytes/element
212 *  \param messagePtr   Pointer to the free message buffer payload (not including message header) or NULL if no free message buffers are available
213 *
214 * This function is used to retrieve a free message buffer for the given inbound queue of at least
215 * messageSize bytes.
216 * The caller can use the returned buffer to construct the message and then call mpiMsgProduce()
217 * to deliver the message to the device message unit or mpiMsgInvalidate() if the message buffer
218 * is not going to be used
219 *
220 * Return:
221 *         AGSA_RC_SUCCESS if messagePtr contains a valid message buffer pointer
222 *         AGSA_RC_FAILURE if messageSize larger than the elementSize of queue
223 *         AGSA_RC_BUSY    if there are not free message buffers (Queue full)
224 */
225/*******************************************************************************/
226GLOBAL FORCEINLINE
227bit32
228mpiMsgFreeGet(
229  mpiICQueue_t *circularQ,
230  bit16 messageSize,
231  void** messagePtr
232  )
233{
234  bit32 offset;
235  agsaRoot_t          *agRoot=circularQ->agRoot;
236  mpiMsgHeader_t *msgHeader;
237  bit8 bcCount = 1; /* only support single buffer */
238
239  SA_DBG4(("Entering function:mpiMsgFreeGet\n"));
240  SA_ASSERT(NULL != circularQ, "circularQ cannot be null");
241  SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null");
242  SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0");
243
244  /* Checks is the requested message size can be allocated in this queue */
245  if(messageSize > circularQ->elementSize)
246  {
247    SA_DBG1(("mpiMsgFreeGet: Message Size (%d) is larger than Q element size (%d)\n",messageSize,circularQ->elementSize));
248    return AGSA_RC_FAILURE;
249  }
250
251  /* Stores the new consumer index */
252  OSSA_READ_LE_32(circularQ->agRoot, &circularQ->consumerIdx, circularQ->ciPointer, 0);
253  /* if inbound queue is full, return busy */
254  /* This queue full logic may only works for bc == 1 ( == ) */
255  /* ( pi + bc ) % size > ci not fully works for bc > 1 */
256  /* To do - support bc > 1 case and wrap around case */
257  if (((circularQ->producerIdx + bcCount) % circularQ->numElements) == circularQ->consumerIdx)
258  {
259    *messagePtr = NULL;
260    smTrace(hpDBG_VERY_LOUD,"Za", (((circularQ->producerIdx & 0xFFF) << 16) |  (circularQ->consumerIdx & 0xFFF) ));
261    /* TP:Za IQ PI CI */
262    ossaHwRegRead(agRoot, MSGU_HOST_SCRATCH_PAD_0);
263    SA_DBG1(("mpiMsgFreeGet: %d + %d == %d AGSA_RC_BUSY\n",circularQ->producerIdx,bcCount,circularQ->consumerIdx));
264
265    return AGSA_RC_BUSY;
266  }
267
268  smTrace(hpDBG_VERY_LOUD,"Zb", (((circularQ->producerIdx & 0xFFF) << 16) |  (circularQ->consumerIdx & 0xFFF) ));
269  /* TP:Zb IQ PI CI */
270
271
272  /* get memory IOMB buffer address */
273  offset = circularQ->producerIdx * circularQ->elementSize;
274  /* increment to next bcCount element */
275  circularQ->producerIdx = (circularQ->producerIdx + bcCount) % circularQ->numElements;
276
277  /* Adds that distance to the base of the region virtual address plus the message header size*/
278  msgHeader = (mpiMsgHeader_t*) (((bit8 *)(circularQ->memoryRegion.virtPtr)) + offset);
279
280  SA_DBG3(("mpiMsgFreeGet: msgHeader = %p Offset = 0x%x\n", (void *)msgHeader, offset));
281
282  /* Sets the message buffer in "allocated" state */
283  /* bc always is 1 for inbound queue */
284  /* temporarily store it in the native endian format, when the rest of the */
285  /* header is filled, this would be converted to Little Endian */
286  msgHeader->Header = (1<<24);
287  *messagePtr = ((bit8*)msgHeader) + sizeof(mpiMsgHeader_t);
288
289  return AGSA_RC_SUCCESS;
290}
291
292#ifdef LOOPBACK_MPI
293GLOBAL bit32 mpiMsgFreeGetOQ(mpiOCQueue_t *circularQ, bit16 messageSize, void** messagePtr)
294{
295  bit32 offset;
296  mpiMsgHeader_t *msgHeader;
297  bit8 bcCount = 1; /* only support single buffer */
298
299  SA_DBG4(("Entering function:mpiMsgFreeGet\n"));
300  SA_ASSERT(NULL != circularQ, "circularQ cannot be null");
301  SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null");
302  SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0");
303
304  /* Checks is the requested message size can be allocated in this queue */
305  if(messageSize > circularQ->elementSize)
306  {
307    SA_DBG1(("mpiMsgFreeGet: Message Size is not fit in\n"));
308    return AGSA_RC_FAILURE;
309  }
310
311  /* Stores the new consumer index */
312  //OSSA_READ_LE_32(circularQ->agRoot, &circularQ->consumerIdx, circularQ->ciPointer, 0);
313  /* if inbound queue is full, return busy */
314  /* This queue full logic may only works for bc == 1 ( == ) */
315  /* ( pi + bc ) % size > ci not fully works for bc > 1 */
316  /* To do - support bc > 1 case and wrap around case */
317  if (((circularQ->producerIdx + bcCount) % circularQ->numElements) == circularQ->consumerIdx)
318  {
319    *messagePtr = NULL;
320    return AGSA_RC_BUSY;
321  }
322
323  /* get memory IOMB buffer address */
324  offset = circularQ->producerIdx * circularQ->elementSize;
325  /* increment to next bcCount element */
326  circularQ->producerIdx = (circularQ->producerIdx + bcCount) % circularQ->numElements;
327
328  /* Adds that distance to the base of the region virtual address plus the message header size*/
329  msgHeader = (mpiMsgHeader_t*) (((bit8 *)(circularQ->memoryRegion.virtPtr)) + offset);
330
331  SA_DBG3(("mpiMsgFreeGet: msgHeader = %p Offset = 0x%x\n", (void *)msgHeader, offset));
332
333  /* Sets the message buffer in "allocated" state */
334  /* bc always is 1 for inbound queue */
335  /* temporarily store it in the native endian format, when the rest of the */
336  /* header is filled, this would be converted to Little Endian */
337  msgHeader->Header = (1<<24);
338  *messagePtr = ((bit8*)msgHeader) + sizeof(mpiMsgHeader_t);
339
340  return AGSA_RC_SUCCESS;
341}
342#endif
343
344/*******************************************************************************/
345/** \fn mpiMsgProduce(mpiICQueue_t *circularQ, void *messagePtr, mpiMsgCategory_t category, bit16 opCode, bit8 responseQueue)
346 *  \brief Add a header of IOMB then send to a inbound queue and update the Producer index
347 *  \param circularQ     Pointer to an inbound queue
348 *  \param messagePtr    Pointer to the message buffer payload (not including message header))
349 *  \param category      Message category (ETHERNET, FC, SAS-SATA, SCSI)
350 *  \param opCode        Message operation code
351 *  \param responseQueue If the message requires response, this paramater indicates the outbound queue for the response
352 *
353 * This function is used to sumit a message buffer, previously obtained from  mpiMsgFreeGet()
354 * function call, to the given Inbound queue
355 *
356 * Return:
357 *         AGSA_RC_SUCCESS if the message has been posted succesfully
358 */
359/*******************************************************************************/
360#ifdef FAST_IO_TEST
361GLOBAL bit32 mpiMsgPrepare(
362                       mpiICQueue_t *circularQ,
363                       void         *messagePtr,
364                       mpiMsgCategory_t category,
365                       bit16        opCode,
366                       bit8         responseQueue,
367                       bit8         hiPriority
368                       )
369{
370  mpiMsgHeader_t *msgHeader;
371  bit32          bc;
372  bit32          Header = 0;
373  bit32          hpriority = 0;
374
375  SA_DBG4(("Entering function:mpiMsgProduce\n"));
376  SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null");
377  SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null");
378  SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue"
379            " is 0");
380  SA_ASSERT(MPI_MAX_OUTBOUND_QUEUES > responseQueue, "oQueue ID is wrong");
381
382  /* Obtains the address of the entire message buffer, including the header */
383  msgHeader = (mpiMsgHeader_t*)(((bit8*)messagePtr) - sizeof(mpiMsgHeader_t));
384  /* Read the BC from header, its stored in native endian format when message
385     was allocated */
386  /* intially */
387  bc = (((msgHeader->Header) >> SHIFT24) & BC_MASK);
388  SA_DBG6(("mpiMsgProduce: msgHeader bc %d\n", bc));
389  if (circularQ->priority)
390    hpriority = 1;
391
392  /* Checks the message is in "allocated" state */
393  SA_ASSERT(0 != bc, "The message buffer is not in \"allocated\" state "
394                     "(bc == 0)");
395
396  Header = ((V_BIT << SHIFT31) | (hpriority << SHIFT30)  |
397            ((bc & BC_MASK) << SHIFT24) |
398            ((responseQueue & OBID_MASK) << SHIFT16) |
399            ((category  & CAT_MASK) << SHIFT12 ) | (opCode & OPCODE_MASK));
400
401  /* pre flush the IOMB cache line */
402  ossaCachePreFlush(circularQ->agRoot,
403                    (void *)circularQ->memoryRegion.appHandle,
404                    (void *)msgHeader, circularQ->elementSize * bc);
405  OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t,
406                   Header), Header);
407  /* flush the IOMB cache line */
408  ossaCacheFlush(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle,
409                 (void *)msgHeader, circularQ->elementSize * bc);
410
411  MPI_DEBUG_TRACE( circularQ->qNumber,
412                  ((circularQ->producerIdx << 16 ) | circularQ->consumerIdx),
413                   MPI_DEBUG_TRACE_IBQ,
414                  (void *)msgHeader,
415                  circularQ->elementSize);
416
417  ossaLogIomb(circularQ->agRoot,
418              circularQ->qNumber,
419              TRUE,
420              (void *)msgHeader,
421              circularQ->elementSize);
422
423  return AGSA_RC_SUCCESS;
424} /* mpiMsgPrepare */
425
426GLOBAL bit32 mpiMsgProduce(
427                       mpiICQueue_t *circularQ,
428                       void         *messagePtr,
429                       mpiMsgCategory_t category,
430                       bit16        opCode,
431                       bit8         responseQueue,
432                       bit8         hiPriority
433                       )
434{
435  bit32 ret;
436
437  ret = mpiMsgPrepare(circularQ, messagePtr, category, opCode, responseQueue,
438                      hiPriority);
439  if (ret == AGSA_RC_SUCCESS)
440  {
441    /* update PI of inbound queue */
442    ossaHwRegWriteExt(circularQ->agRoot,
443                      circularQ->PIPCIBar,
444                      circularQ->PIPCIOffset,
445                      circularQ->producerIdx);
446  }
447  return ret;
448}
449
450GLOBAL void mpiIBQMsgSend(mpiICQueue_t *circularQ)
451{
452  ossaHwRegWriteExt(circularQ->agRoot,
453                    circularQ->PIPCIBar,
454                    circularQ->PIPCIOffset,
455                    circularQ->producerIdx);
456}
457#else  /* FAST_IO_TEST */
458
459GLOBAL FORCEINLINE
460bit32
461mpiMsgProduce(
462  mpiICQueue_t *circularQ,
463  void *messagePtr,
464  mpiMsgCategory_t category,
465  bit16 opCode,
466  bit8 responseQueue,
467  bit8 hiPriority
468  )
469{
470  mpiMsgHeader_t *msgHeader;
471  bit32          bc;
472  bit32          Header = 0;
473  bit32          hpriority = 0;
474
475#ifdef SA_FW_TEST_BUNCH_STARTS
476#define Need_agRootDefined 1
477#endif /* SA_FW_TEST_BUNCH_STARTS */
478
479#ifdef SA_ENABLE_TRACE_FUNCTIONS
480  bit32             i;
481#define Need_agRootDefined 1
482#endif /* SA_ENABLE_TRACE_FUNCTIONS */
483
484#ifdef MPI_DEBUG_TRACE_ENABLE
485#define Need_agRootDefined 1
486#endif /* MPI_DEBUG_TRACE_ENABLE */
487
488#ifdef Need_agRootDefined
489  agsaRoot_t   *agRoot=circularQ->agRoot;
490#ifdef SA_FW_TEST_BUNCH_STARTS
491   agsaLLRoot_t *saRoot = agNULL;
492  saRoot = agRoot->sdkData;
493#endif /* SA_FW_TEST_BUNCH_STARTS */
494
495#undef Need_agRootDefined
496#endif /* Need_agRootDefined */
497
498  SA_DBG4(("Entering function:mpiMsgProduce\n"));
499  SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null");
500  SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null");
501  SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0");
502  SA_ASSERT(MPI_MAX_OUTBOUND_QUEUES > responseQueue, "oQueue ID is wrong");
503
504  /* REB Start extra trace */
505  smTraceFuncEnter(hpDBG_VERY_LOUD,"22");
506  /* REB End extra trace */
507
508  /* Obtains the address of the entire message buffer, including the header */
509  msgHeader = (mpiMsgHeader_t*)(((bit8*)messagePtr) - sizeof(mpiMsgHeader_t));
510  /* Read the BC from header, its stored in native endian format when message was allocated */
511  /* intially */
512  bc = (((msgHeader->Header) >> SHIFT24) & BC_MASK);
513  SA_DBG6(("mpiMsgProduce: msgHeader bc %d\n", bc));
514  if (circularQ->priority)
515  {
516    hpriority = 1;
517  }
518
519  /* Checks the message is in "allocated" state */
520  SA_ASSERT(0 != bc, "The message buffer is not in \"allocated\" state (bc == 0)");
521
522  Header = ((V_BIT << SHIFT31) |
523            (hpriority << SHIFT30)  |
524            ((bc & BC_MASK) << SHIFT24) |
525            ((responseQueue & OBID_MASK) << SHIFT16) |
526            ((category  & CAT_MASK) << SHIFT12 ) |
527            (opCode & OPCODE_MASK));
528
529  /* pre flush the cache line */
530  ossaCachePreFlush(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, (void *)msgHeader, circularQ->elementSize * bc);
531  OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t, Header), Header);
532  /* flush the cache line for IOMB */
533  ossaCacheFlush(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, (void *)msgHeader, circularQ->elementSize * bc);
534
535  MPI_DEBUG_TRACE( circularQ->qNumber,
536                  ((circularQ->producerIdx << 16 ) | circularQ->consumerIdx),
537                  MPI_DEBUG_TRACE_IBQ,
538                  (void *)msgHeader,
539                  circularQ->elementSize);
540
541  ossaLogIomb(circularQ->agRoot,
542              circularQ->qNumber,
543              TRUE,
544              (void *)msgHeader,
545              circularQ->elementSize);
546
547#if defined(SALLSDK_DEBUG)
548  MPI_IBQ_IOMB_LOG(circularQ->qNumber, (void *)msgHeader, circularQ->elementSize);
549#endif  /* SALLSDK_DEBUG */
550  /* REB Start extra trace */
551#ifdef SA_ENABLE_TRACE_FUNCTIONS
552  smTrace(hpDBG_IOMB,"M1",circularQ->qNumber);
553 /* TP:M1 circularQ->qNumber */
554  for (i=0; i<((bit32)bc*(circularQ->elementSize/4)); i++)
555  {
556      /* The -sizeof(mpiMsgHeader_t) is to account for mpiMsgProduce adding the header to the pMessage pointer */
557      smTrace(hpDBG_IOMB,"MD",*( ((bit32 *)((bit8 *)messagePtr - sizeof(mpiMsgHeader_t))) + i));
558      /* TP:MD Inbound IOMB Dword */
559  }
560#endif /* SA_ENABLE_TRACE_FUNCTIONS */
561
562  /* update PI of inbound queue */
563
564#ifdef SA_FW_TEST_BUNCH_STARTS
565  if(saRoot->BunchStarts_Enable)
566  {
567      if (circularQ->BunchStarts_QPending == 0)
568      {
569          // store tick value for 1st deferred IO only
570          circularQ->BunchStarts_QPendingTick = saRoot->timeTick;
571      }
572      // update queue's pending count
573      circularQ->BunchStarts_QPending++;
574
575      // update global pending count
576      saRoot->BunchStarts_Pending++;
577
578      SA_DBG1(("mpiMsgProduce: BunchStarts - Global Pending %d\n", saRoot->BunchStarts_Pending));
579      SA_DBG1(("mpiMsgProduce: BunchStarts - QPending %d, Q-%d\n", circularQ->BunchStarts_QPending, circularQ->qNumber));
580      smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "22");
581
582      return AGSA_RC_SUCCESS;
583  }
584
585  saRoot->BunchStarts_Pending     = 0;
586  circularQ->BunchStarts_QPending = 0;
587#endif /* SA_FW_TEST_BUNCH_STARTS */
588  ossaHwRegWriteExt(circularQ->agRoot,
589                    circularQ->PIPCIBar,
590                    circularQ->PIPCIOffset,
591                    circularQ->producerIdx);
592
593  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "22");
594
595  return AGSA_RC_SUCCESS;
596} /* mpiMsgProduce */
597#endif /* FAST_IO_TEST */
598
599#ifdef SA_FW_TEST_BUNCH_STARTS
600
601void mpiMsgProduceBunch(  agsaLLRoot_t  *saRoot)
602{
603  mpiICQueue_t *circularQ;
604  bit32 inq;
605
606  for(inq=0; ((inq < saRoot->QueueConfig.numInboundQueues) && saRoot->BunchStarts_Pending); inq++)
607  {
608    circularQ= &saRoot->inboundQueue[inq];
609    /* If any pending IOs present then either process if BunchStarts_Threshold
610     * IO limit reached or if the timer has popped
611     */
612    if (circularQ->BunchStarts_QPending &&
613        ((circularQ->BunchStarts_QPending >= saRoot->BunchStarts_Threshold) ||
614         ((saRoot->timeTick - circularQ->BunchStarts_QPendingTick) >= saRoot->BunchStarts_TimeoutTicks))
615       )
616    {
617      if(circularQ->qNumber != inq)
618      {
619        SA_DBG1(("mpiMsgProduceBunch:circularQ->qNumber(%d) != inq(%d)\n",circularQ->qNumber, inq));
620      }
621
622      SA_DBG1(("mpiMsgProduceBunch: IQ=%d, PI=%d\n", inq, circularQ->producerIdx));
623      SA_DBG1(("mpiMsgProduceBunch: Qpending=%d, TotPending=%d\n", circularQ->BunchStarts_QPending, saRoot->BunchStarts_Pending));
624
625      ossaHwRegWriteExt(circularQ->agRoot,
626                     circularQ->PIPCIBar,
627                     circularQ->PIPCIOffset,
628                     circularQ->producerIdx);
629
630      // update global pending count
631      saRoot->BunchStarts_Pending -= circularQ->BunchStarts_QPending;
632
633      // clear current queue's pending count after processing
634      circularQ->BunchStarts_QPending = 0;
635      circularQ->BunchStarts_QPendingTick = saRoot->timeTick;
636    }
637  }
638}
639#endif /* SA_FW_TEST_BUNCH_STARTS */
640
641/*******************************************************************************/
642/** \fn mpiMsgConsume(mpiOCQueue_t *circularQ, void *messagePtr1,
643 *                mpiMsgCategory_t * pCategory, bit16 * pOpCode, bit8 * pBC)
644 *  \brief Get a received message
645 *  \param circularQ   Pointer to a outbound queue
646 *  \param messagePtr1 Pointer to the returned message buffer or NULL if no valid message
647 *  \param pCategory   Pointer to Message category (ETHERNET, FC, SAS-SATA, SCSI)
648 *  \param pOpCode     Pointer to Message operation code
649 *  \param pBC         Pointer to buffer count
650 *
651 * Consume a receive message in the specified outbound queue
652 *
653 * Return:
654 *         AGSA_RC_SUCCESS if the message has been retrieved succesfully
655 *         AGSA_RC_BUSY    if the circular is empty
656 */
657/*******************************************************************************/
658GLOBAL FORCEINLINE
659bit32
660mpiMsgConsume(
661  mpiOCQueue_t       *circularQ,
662  void             ** messagePtr1,
663  mpiMsgCategory_t   *pCategory,
664  bit16              *pOpCode,
665  bit8               *pBC
666  )
667{
668  mpiMsgHeader_t *msgHeader;
669  bit32          msgHeader_tmp;
670
671  SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null");
672  SA_ASSERT(NULL != messagePtr1, "messagePtr1 argument cannot be null");
673  SA_ASSERT(NULL != pCategory, "pCategory argument cannot be null");
674  SA_ASSERT(NULL != pOpCode, "pOpCode argument cannot be null");
675  SA_ASSERT(NULL != pBC, "pBC argument cannot be null");
676  SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0");
677
678  do
679  {
680    /* If there are not-yet-delivered messages ... */
681    if(circularQ->producerIdx != circularQ->consumerIdx)
682    {
683      /* Get the pointer to the circular queue buffer element */
684      msgHeader = (mpiMsgHeader_t*) ((bit8 *)(circularQ->memoryRegion.virtPtr) + circularQ->consumerIdx * circularQ->elementSize);
685
686#ifdef LOOPBACK_MPI
687      if (!loopback)
688#endif
689      /* invalidate the cache line of IOMB */
690      ossaCacheInvalidate(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, (void *)msgHeader, circularQ->elementSize);
691
692
693      /* read header */
694      OSSA_READ_LE_32(circularQ->agRoot, &msgHeader_tmp, msgHeader, 0);
695
696      SA_DBG4(("mpiMsgConsume: process an IOMB, header=0x%x\n", msgHeader_tmp));
697
698      SA_ASSERT(0 != (msgHeader_tmp & HEADER_BC_MASK), "The bc field in the header is 0");
699#ifdef TEST
700      /* for debugging */
701      if (0 == (msgHeader_tmp & HEADER_BC_MASK))
702      {
703        SA_DBG1(("mpiMsgConsume: CI=%d PI=%d msgHeader=%p\n", circularQ->consumerIdx, circularQ->producerIdx, (void *)msgHeader));
704        circularQ->consumerIdx = (circularQ->consumerIdx + 1) % circularQ->numElements;
705        /* update the CI of outbound queue - skip this blank IOMB, for test only */
706        ossaHwRegWriteExt(circularQ->agRoot,
707                          circularQ->CIPCIBar,
708                          circularQ->CIPCIOffset,
709                          circularQ->consumerIdx);
710        return AGSA_RC_FAILURE;
711      }
712#endif
713      /* get message pointer of valid entry */
714      if (0 != (msgHeader_tmp & HEADER_V_MASK))
715      {
716        SA_ASSERT(circularQ->consumerIdx <= circularQ->numElements, "Multi-buffer messages cannot wrap around");
717
718        if (OPC_OUB_SKIP_ENTRY != (msgHeader_tmp & OPCODE_MASK))
719        {
720          /* ... return the message payload */
721          *messagePtr1 = ((bit8*)msgHeader) + sizeof(mpiMsgHeader_t);
722          *pCategory   = (mpiMsgCategory_t)(msgHeader_tmp >> SHIFT12) & CAT_MASK;
723          *pOpCode     = (bit16)(msgHeader_tmp & OPCODE_MASK);
724          *pBC         = (bit8)((msgHeader_tmp >> SHIFT24) & BC_MASK);
725
726          /* invalidate the cache line for IOMB */
727#ifdef LOOPBACK_MPI
728          if (!loopback)
729#endif
730            ossaCacheInvalidate(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, (void *)msgHeader, (*pBC - 1) * circularQ->elementSize);
731
732#if defined(SALLSDK_DEBUG)
733          SA_DBG3(("mpiMsgConsume: CI=%d PI=%d msgHeader=%p\n", circularQ->consumerIdx, circularQ->producerIdx, (void *)msgHeader));
734          MPI_OBQ_IOMB_LOG(circularQ->qNumber, (void *)msgHeader, circularQ->elementSize);
735#endif
736          return AGSA_RC_SUCCESS;
737        }
738        else
739        {
740          SA_DBG3(("mpiMsgConsume: SKIP_ENTRIES_IOMB BC=%d\n", (msgHeader_tmp >> SHIFT24) & BC_MASK));
741          /* Updated comsumerIdx and skip it */
742          circularQ->consumerIdx = (circularQ->consumerIdx + ((msgHeader_tmp >> SHIFT24) & BC_MASK)) % circularQ->numElements;
743          /* clean header to 0 */
744          msgHeader_tmp = 0;
745          /*ossaSingleThreadedEnter(agRoot, LL_IOREQ_OBQ_LOCK);*/
746
747          OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t, Header), msgHeader_tmp);
748
749          /* update the CI of outbound queue */
750          ossaHwRegWriteExt(circularQ->agRoot,
751                            circularQ->CIPCIBar,
752                            circularQ->CIPCIOffset,
753                            circularQ->consumerIdx);
754          /* Update the producer index */
755          OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0);
756          /*ossaSingleThreadedLeave(agRoot, LL_IOREQ_OBQ_LOCK); */
757        }
758      }
759      else
760      {
761        /* V bit is not set */
762#if defined(SALLSDK_DEBUG)
763        agsaRoot_t *agRoot=circularQ->agRoot;
764        SA_DBG1(("mpiMsgConsume: V bit not set, PI=%d CI=%d msgHeader=%p\n",  circularQ->producerIdx, circularQ->consumerIdx,(void *)msgHeader));
765        SA_DBG1(("mpiMsgConsume: V bit not set, 0x%08X Q=%d  \n", msgHeader_tmp, circularQ->qNumber));
766
767        MPI_DEBUG_TRACE(MPI_DEBUG_TRACE_QNUM_ERROR + circularQ->qNumber,
768                        ((circularQ->producerIdx << 16 ) | circularQ->consumerIdx),
769                          MPI_DEBUG_TRACE_OBQ,
770                         (void *)(((bit8*)msgHeader) - sizeof(mpiMsgHeader_t)),
771                          circularQ->elementSize);
772
773        circularQ->consumerIdx = circularQ->consumerIdx % circularQ->numElements;
774        circularQ->consumerIdx ++;
775        OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t, Header), msgHeader_tmp);
776        ossaHwRegWriteExt(agRoot,
777                          circularQ->CIPCIBar,
778                          circularQ->CIPCIOffset,
779                          circularQ->consumerIdx);
780        MPI_OBQ_IOMB_LOG(circularQ->qNumber, (void *)msgHeader, circularQ->elementSize);
781#endif
782        SA_DBG1(("mpiMsgConsume: V bit is not set!!!!! HW CI=%d\n", ossaHwRegReadExt(circularQ->agRoot, circularQ->CIPCIBar, circularQ->CIPCIOffset) ));
783        SA_ASSERT(0, "V bit is not set");
784        return AGSA_RC_FAILURE;
785      }
786    }
787    else
788    {
789      /* Update the producer index from SPC */
790      OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0);
791    }
792  } while(circularQ->producerIdx != circularQ->consumerIdx); /* while we don't have any more not-yet-delivered message */
793
794#ifdef TEST
795  SA_DBG4(("mpiMsgConsume: Outbound queue is empty.\n"));
796#endif
797
798  /* report empty */
799  return AGSA_RC_BUSY;
800}
801
802/*******************************************************************************/
803/** \fn mpiMsgFreeSet(mpiOCQueue_t *circularQ, void *messagePtr)
804 *  \brief Returns a received message to the outbound queue
805 *  \param circularQ   Pointer to an outbound queue
806 *  \param messagePtr1 Pointer to the returned message buffer to free
807 *  \param messagePtr2 Pointer to the returned message buffer to free if bc > 1
808 *
809 * Returns consumed and processed message to the the specified outbounf queue
810 *
811 * Return:
812 *         AGSA_RC_SUCCESS if the message has been returned succesfully
813 */
814/*******************************************************************************/
815GLOBAL FORCEINLINE
816bit32
817mpiMsgFreeSet(
818  mpiOCQueue_t *circularQ,
819  void *messagePtr1,
820  bit8 bc
821  )
822{
823  mpiMsgHeader_t     *msgHeader;
824
825  SA_DBG4(("Entering function:mpiMsgFreeSet\n"));
826  SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null");
827  SA_ASSERT(NULL != messagePtr1, "messagePtr1 argument cannot be null");
828  SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0");
829
830  /* Obtains the address of the entire message buffer, including the header */
831  msgHeader = (mpiMsgHeader_t*)(((bit8*)messagePtr1) - sizeof(mpiMsgHeader_t));
832
833  if ( ((mpiMsgHeader_t*)((bit8*)circularQ->memoryRegion.virtPtr + circularQ->consumerIdx * circularQ->elementSize)) != msgHeader)
834  {
835    /* IOMB of CI points mismatch with Message Header - should never happened */
836    SA_DBG1(("mpiMsgFreeSet: Wrong CI, Q %d ConsumeIdx = %d msgHeader 0x%08x\n",circularQ->qNumber, circularQ->consumerIdx ,msgHeader->Header));
837    SA_DBG1(("mpiMsgFreeSet: msgHeader %p != %p\n", msgHeader,((mpiMsgHeader_t*)((bit8*)circularQ->memoryRegion.virtPtr + circularQ->consumerIdx * circularQ->elementSize))));
838
839#ifdef LOOPBACK_MPI
840    if (!loopback)
841#endif
842    /* Update the producer index from SPC */
843    OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0);
844#if defined(SALLSDK_DEBUG)
845    SA_DBG3(("mpiMsgFreeSet: ProducerIdx = %d\n", circularQ->producerIdx));
846#endif
847    return AGSA_RC_SUCCESS;
848  }
849
850  /* ... free the circular queue buffer elements associated with the message ... */
851  /*... by incrementing the consumer index (with wrap arround) */
852  circularQ->consumerIdx = (circularQ->consumerIdx + bc) % circularQ->numElements;
853
854  /* Invalidates this circular queue buffer element */
855
856  msgHeader->Header &= ~HEADER_V_MASK; /* Clear Valid bit to indicate IOMB consumed by host */
857  SA_ASSERT(circularQ->consumerIdx <= circularQ->numElements, "Multi-buffer messages cannot wrap arround");
858
859  /* update the CI of outbound queue */
860#ifdef LOOPBACK_MPI
861  if (!loopback)
862#endif
863  {
864  ossaHwRegWriteExt(circularQ->agRoot,
865                    circularQ->CIPCIBar,
866                    circularQ->CIPCIOffset,
867                    circularQ->consumerIdx);
868
869  /* Update the producer index from SPC */
870  OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0);
871  }
872#if defined(SALLSDK_DEBUG)
873  SA_DBG5(("mpiMsgFreeSet: CI=%d PI=%d\n", circularQ->consumerIdx, circularQ->producerIdx));
874#endif
875  return AGSA_RC_SUCCESS;
876}
877
878#ifdef TEST
879GLOBAL bit32 mpiRotateQnumber(agsaRoot_t *agRoot)
880{
881  agsaLLRoot_t *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
882  bit32        denom;
883  bit32        ret = 0;
884
885  /* inbound queue number */
886  saRoot->IBQnumber++;
887  denom = saRoot->QueueConfig.numInboundQueues;
888  if (saRoot->IBQnumber % denom == 0) /* % Qnumber*/
889  {
890    saRoot->IBQnumber = 0;
891  }
892  SA_DBG3(("mpiRotateQnumber: IBQnumber %d\n", saRoot->IBQnumber));
893
894  /* outbound queue number */
895  saRoot->OBQnumber++;
896  denom = saRoot->QueueConfig.numOutboundQueues;
897  if (saRoot->OBQnumber % denom == 0) /* % Qnumber*/
898  {
899    saRoot->OBQnumber = 0;
900  }
901  SA_DBG3(("mpiRotateQnumber: OBQnumber %d\n", saRoot->OBQnumber));
902
903  ret = (saRoot->OBQnumber << SHIFT16) | saRoot->IBQnumber;
904  return ret;
905}
906#endif
907
908#ifdef LOOPBACK_MPI
909GLOBAL bit32 mpiMsgProduceOQ(
910                       mpiOCQueue_t *circularQ,
911                       void         *messagePtr,
912                       mpiMsgCategory_t category,
913                       bit16        opCode,
914                       bit8         responseQueue,
915                       bit8         hiPriority
916                       )
917{
918  mpiMsgHeader_t *msgHeader;
919  bit32          bc;
920  bit32          Header = 0;
921  bit32          hpriority = 0;
922
923  SA_DBG4(("Entering function:mpiMsgProduceOQ\n"));
924  SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null");
925  SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null");
926  SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue"
927            " is 0");
928  SA_ASSERT(MPI_MAX_OUTBOUND_QUEUES > responseQueue, "oQueue ID is wrong");
929
930  /* REB Start extra trace */
931  smTraceFuncEnter(hpDBG_VERY_LOUD, "2I");
932  /* REB End extra trace */
933
934  /* Obtains the address of the entire message buffer, including the header */
935  msgHeader = (mpiMsgHeader_t*)(((bit8*)messagePtr) - sizeof(mpiMsgHeader_t));
936  /* Read the BC from header, its stored in native endian format when message
937     was allocated */
938  /* intially */
939  SA_DBG4(("mpiMsgProduceOQ: msgHeader %p opcode %d pi/ci %d / %d\n", msgHeader, opCode, circularQ->producerIdx, circularQ->consumerIdx));
940  bc = (((msgHeader->Header) >> SHIFT24) & BC_MASK);
941  SA_DBG6(("mpiMsgProduceOQ: msgHeader bc %d\n", bc));
942  if (circularQ->priority)
943    hpriority = 1;
944
945  /* Checks the message is in "allocated" state */
946  SA_ASSERT(0 != bc, "The message buffer is not in \"allocated\" state "
947                     "(bc == 0)");
948
949  Header = ((V_BIT << SHIFT31) | (hpriority << SHIFT30)  |
950            ((bc & BC_MASK) << SHIFT24) |
951            ((responseQueue & OBID_MASK) << SHIFT16) |
952            ((category  & CAT_MASK) << SHIFT12 ) | (opCode & OPCODE_MASK));
953  /* pre flush the IOMB cache line */
954  //ossaCachePreFlush(circularQ->agRoot,
955  //                  (void *)circularQ->memoryRegion.appHandle,
956  //                  (void *)msgHeader, circularQ->elementSize * bc);
957  OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t,
958                   Header), Header);
959
960  /* flush the IOMB cache line */
961  //ossaCacheFlush(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle,
962  //               (void *)msgHeader, circularQ->elementSize * bc);
963
964  MPI_DEBUG_TRACE( circularQ->qNumber,
965                 ((circularQ->producerIdx << 16 ) | circularQ->consumerIdx),
966                  MPI_DEBUG_TRACE_OBQ,
967                  (void *)msgHeader,
968                  circularQ->elementSize);
969
970  ossaLogIomb(circularQ->agRoot,
971              circularQ->qNumber,
972              TRUE,
973              (void *)msgHeader,
974              circularQ->elementSize);
975
976  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2I");
977  return AGSA_RC_SUCCESS;
978} /* mpiMsgProduceOQ */
979#endif
980
981