xref: /freebsd/sys/dev/pms/RefTisa/sallsdk/spc/sasmp.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1*4e1bc9a0SAchim Leubner /*******************************************************************************
2*4e1bc9a0SAchim Leubner *Copyright (c) 2014 PMC-Sierra, Inc.  All rights reserved.
3*4e1bc9a0SAchim Leubner *
4*4e1bc9a0SAchim Leubner *Redistribution and use in source and binary forms, with or without modification, are permitted provided
5*4e1bc9a0SAchim Leubner *that the following conditions are met:
6*4e1bc9a0SAchim Leubner *1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
7*4e1bc9a0SAchim Leubner *following disclaimer.
8*4e1bc9a0SAchim Leubner *2. Redistributions in binary form must reproduce the above copyright notice,
9*4e1bc9a0SAchim Leubner *this list of conditions and the following disclaimer in the documentation and/or other materials provided
10*4e1bc9a0SAchim Leubner *with the distribution.
11*4e1bc9a0SAchim Leubner *
12*4e1bc9a0SAchim Leubner *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
13*4e1bc9a0SAchim Leubner *WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14*4e1bc9a0SAchim Leubner *FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
15*4e1bc9a0SAchim Leubner *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16*4e1bc9a0SAchim Leubner *NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
17*4e1bc9a0SAchim Leubner *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18*4e1bc9a0SAchim Leubner *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19*4e1bc9a0SAchim Leubner *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
20*4e1bc9a0SAchim Leubner 
21*4e1bc9a0SAchim Leubner ********************************************************************************/
22*4e1bc9a0SAchim Leubner /*******************************************************************************/
23*4e1bc9a0SAchim Leubner /*! \file sasmp.c
24*4e1bc9a0SAchim Leubner  *  \brief The file implements the functions for SMP request/response
25*4e1bc9a0SAchim Leubner  *
26*4e1bc9a0SAchim Leubner  */
27*4e1bc9a0SAchim Leubner /*******************************************************************************/
28*4e1bc9a0SAchim Leubner #include <sys/cdefs.h>
29*4e1bc9a0SAchim Leubner #include <dev/pms/config.h>
30*4e1bc9a0SAchim Leubner 
31*4e1bc9a0SAchim Leubner #include <dev/pms/RefTisa/sallsdk/spc/saglobal.h>
32*4e1bc9a0SAchim Leubner #ifdef SA_ENABLE_TRACE_FUNCTIONS
33*4e1bc9a0SAchim Leubner #ifdef siTraceFileID
34*4e1bc9a0SAchim Leubner #undef siTraceFileID
35*4e1bc9a0SAchim Leubner #endif
36*4e1bc9a0SAchim Leubner #define siTraceFileID 'N'
37*4e1bc9a0SAchim Leubner #endif
38*4e1bc9a0SAchim Leubner 
39*4e1bc9a0SAchim Leubner /******************************************************************************/
40*4e1bc9a0SAchim Leubner /*! \brief Start SMP request
41*4e1bc9a0SAchim Leubner  *
42*4e1bc9a0SAchim Leubner  *  Start SMP request
43*4e1bc9a0SAchim Leubner  *
44*4e1bc9a0SAchim Leubner  *  \param agRoot handles for this instance of SAS/SATA hardware
45*4e1bc9a0SAchim Leubner  *  \param queueNum
46*4e1bc9a0SAchim Leubner  *  \param agIORequest
47*4e1bc9a0SAchim Leubner  *  \param agDevHandle
48*4e1bc9a0SAchim Leubner  *  \param agRequestType
49*4e1bc9a0SAchim Leubner  *  \param agRequestBody
50*4e1bc9a0SAchim Leubner  *  \param agCB
51*4e1bc9a0SAchim Leubner  * Spc - support    direct mode direct response
52*4e1bc9a0SAchim Leubner  * SpcV - support   direct mode direct response
53*4e1bc9a0SAchim Leubner  * SpcV - support indirect mode  direct response
54*4e1bc9a0SAchim Leubner  * SpcV - support indirect mode indirect response
55*4e1bc9a0SAchim Leubner  *
56*4e1bc9a0SAchim Leubner  *  \return If request is started successfully
57*4e1bc9a0SAchim Leubner  *          - \e AGSA_RC_SUCCESS request is started successfully
58*4e1bc9a0SAchim Leubner  *          - \e AGSA_RC_BUSY No resource available, try again later
59*4e1bc9a0SAchim Leubner  */
60*4e1bc9a0SAchim Leubner /*******************************************************************************/
saSMPStart(agsaRoot_t * agRoot,agsaIORequest_t * agIORequest,bit32 queueNum,agsaDevHandle_t * agDevHandle,bit32 agRequestType,agsaSASRequestBody_t * agRequestBody,ossaSMPCompletedCB_t agCB)61*4e1bc9a0SAchim Leubner GLOBAL bit32 saSMPStart(
62*4e1bc9a0SAchim Leubner   agsaRoot_t            *agRoot,
63*4e1bc9a0SAchim Leubner   agsaIORequest_t       *agIORequest,
64*4e1bc9a0SAchim Leubner   bit32                 queueNum,
65*4e1bc9a0SAchim Leubner   agsaDevHandle_t       *agDevHandle,
66*4e1bc9a0SAchim Leubner   bit32                 agRequestType,
67*4e1bc9a0SAchim Leubner   agsaSASRequestBody_t  *agRequestBody,
68*4e1bc9a0SAchim Leubner   ossaSMPCompletedCB_t  agCB
69*4e1bc9a0SAchim Leubner   )
70*4e1bc9a0SAchim Leubner {
71*4e1bc9a0SAchim Leubner   bit32                     ret = AGSA_RC_SUCCESS, retVal;
72*4e1bc9a0SAchim Leubner   agsaLLRoot_t              *saRoot = agNULL;
73*4e1bc9a0SAchim Leubner   mpiICQueue_t              *circularQ;
74*4e1bc9a0SAchim Leubner   agsaDeviceDesc_t          *pDevice;
75*4e1bc9a0SAchim Leubner   agsaPort_t                *pPort;
76*4e1bc9a0SAchim Leubner   agsaIORequestDesc_t       *pRequest;
77*4e1bc9a0SAchim Leubner   void                      *pMessage;
78*4e1bc9a0SAchim Leubner   bit8                      i, inq, outq;
79*4e1bc9a0SAchim Leubner   bit8                      using_reserved = agFALSE;
80*4e1bc9a0SAchim Leubner   bit8                      *payload_ptr;
81*4e1bc9a0SAchim Leubner   agsaSMPFrame_t            *pSMPFrame;
82*4e1bc9a0SAchim Leubner 
83*4e1bc9a0SAchim Leubner   SA_DBG4(("saSMPStart: start\n"));
84*4e1bc9a0SAchim Leubner 
85*4e1bc9a0SAchim Leubner   smTraceFuncEnter(hpDBG_VERY_LOUD, "9a");
86*4e1bc9a0SAchim Leubner 
87*4e1bc9a0SAchim Leubner   /* sanity check */
88*4e1bc9a0SAchim Leubner   SA_ASSERT((agNULL != agRoot), "");
89*4e1bc9a0SAchim Leubner   SA_ASSERT((agNULL != agIORequest), "");
90*4e1bc9a0SAchim Leubner   SA_ASSERT((agNULL != agDevHandle), "");
91*4e1bc9a0SAchim Leubner   SA_ASSERT((agNULL != agRequestBody), "");
92*4e1bc9a0SAchim Leubner 
93*4e1bc9a0SAchim Leubner   /* sanity check */
94*4e1bc9a0SAchim Leubner   saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
95*4e1bc9a0SAchim Leubner   SA_ASSERT((agNULL != saRoot), "");
96*4e1bc9a0SAchim Leubner 
97*4e1bc9a0SAchim Leubner   if(saRoot == agNULL)
98*4e1bc9a0SAchim Leubner   {
99*4e1bc9a0SAchim Leubner     SA_DBG1(("saSMPStart : saRoot is NULL!!\n"));
100*4e1bc9a0SAchim Leubner     return AGSA_RC_FAILURE;
101*4e1bc9a0SAchim Leubner   }
102*4e1bc9a0SAchim Leubner 
103*4e1bc9a0SAchim Leubner   /* Assign inbound and outbound queue number */
104*4e1bc9a0SAchim Leubner   inq = (bit8)(queueNum & MPI_IB_NUM_MASK);
105*4e1bc9a0SAchim Leubner   outq = (bit8)((queueNum & MPI_OB_NUM_MASK) >> MPI_OB_SHIFT);
106*4e1bc9a0SAchim Leubner   SA_ASSERT((AGSA_MAX_INBOUND_Q > inq), "The IBQ Number is out of range.");
107*4e1bc9a0SAchim Leubner 
108*4e1bc9a0SAchim Leubner   /* Find the outgoing port for the device */
109*4e1bc9a0SAchim Leubner   if (agNULL == agDevHandle->sdkData)
110*4e1bc9a0SAchim Leubner   {
111*4e1bc9a0SAchim Leubner     /* Device has been removed */
112*4e1bc9a0SAchim Leubner     SA_DBG1(("saSMPStart, Device has been removed. agDevHandle=%p\n", agDevHandle));
113*4e1bc9a0SAchim Leubner     smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "9a");
114*4e1bc9a0SAchim Leubner     return AGSA_RC_FAILURE;
115*4e1bc9a0SAchim Leubner   }
116*4e1bc9a0SAchim Leubner 
117*4e1bc9a0SAchim Leubner   pDevice = (agsaDeviceDesc_t *) (agDevHandle->sdkData);
118*4e1bc9a0SAchim Leubner 
119*4e1bc9a0SAchim Leubner   pPort = pDevice->pPort;
120*4e1bc9a0SAchim Leubner 
121*4e1bc9a0SAchim Leubner   /* Get request from free IO Requests */
122*4e1bc9a0SAchim Leubner   ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
123*4e1bc9a0SAchim Leubner   pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests)); /**/
124*4e1bc9a0SAchim Leubner 
125*4e1bc9a0SAchim Leubner   /* If no LL IO request entry available */
126*4e1bc9a0SAchim Leubner   if ( agNULL == pRequest )
127*4e1bc9a0SAchim Leubner   {
128*4e1bc9a0SAchim Leubner 
129*4e1bc9a0SAchim Leubner     pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests));
130*4e1bc9a0SAchim Leubner 
131*4e1bc9a0SAchim Leubner     if(agNULL != pRequest)
132*4e1bc9a0SAchim Leubner     {
133*4e1bc9a0SAchim Leubner       using_reserved = agTRUE;
134*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPStart, using saRoot->freeReservedRequests\n"));
135*4e1bc9a0SAchim Leubner     }
136*4e1bc9a0SAchim Leubner     else
137*4e1bc9a0SAchim Leubner     {
138*4e1bc9a0SAchim Leubner       ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
139*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPStart, No request from free list Not using saRoot->freeReservedRequests\n"));
140*4e1bc9a0SAchim Leubner       smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "9a");
141*4e1bc9a0SAchim Leubner       return AGSA_RC_BUSY;
142*4e1bc9a0SAchim Leubner     }
143*4e1bc9a0SAchim Leubner   }
144*4e1bc9a0SAchim Leubner 
145*4e1bc9a0SAchim Leubner   /* If free IOMB avaliable */
146*4e1bc9a0SAchim Leubner   /* Remove the request from free list */
147*4e1bc9a0SAchim Leubner   if( using_reserved )
148*4e1bc9a0SAchim Leubner   {
149*4e1bc9a0SAchim Leubner     saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
150*4e1bc9a0SAchim Leubner   }
151*4e1bc9a0SAchim Leubner   else
152*4e1bc9a0SAchim Leubner   {
153*4e1bc9a0SAchim Leubner     saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
154*4e1bc9a0SAchim Leubner   }
155*4e1bc9a0SAchim Leubner 
156*4e1bc9a0SAchim Leubner   /* Add the request to the pendingSMPRequests list of the device */
157*4e1bc9a0SAchim Leubner   saLlistIOAdd(&(pDevice->pendingIORequests), &(pRequest->linkNode));
158*4e1bc9a0SAchim Leubner   SA_ASSERT((!pRequest->valid), "The pRequest is in use");
159*4e1bc9a0SAchim Leubner   pRequest->valid             = agTRUE;
160*4e1bc9a0SAchim Leubner   ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
161*4e1bc9a0SAchim Leubner 
162*4e1bc9a0SAchim Leubner   /* set up pRequest */
163*4e1bc9a0SAchim Leubner   pRequest->pIORequestContext = agIORequest;
164*4e1bc9a0SAchim Leubner   pRequest->pDevice           = pDevice;
165*4e1bc9a0SAchim Leubner   pRequest->pPort             = pPort;
166*4e1bc9a0SAchim Leubner   pRequest->requestType       = agRequestType;
167*4e1bc9a0SAchim Leubner   pRequest->startTick         = saRoot->timeTick;
168*4e1bc9a0SAchim Leubner   pRequest->completionCB      = (ossaSSPCompletedCB_t)agCB;
169*4e1bc9a0SAchim Leubner 
170*4e1bc9a0SAchim Leubner   /* Set request to the sdkData of agIORequest */
171*4e1bc9a0SAchim Leubner   agIORequest->sdkData        = pRequest;
172*4e1bc9a0SAchim Leubner 
173*4e1bc9a0SAchim Leubner   /* save tag to IOMap */
174*4e1bc9a0SAchim Leubner   saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
175*4e1bc9a0SAchim Leubner   saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
176*4e1bc9a0SAchim Leubner 
177*4e1bc9a0SAchim Leubner #ifdef SA_LL_IBQ_PROTECT
178*4e1bc9a0SAchim Leubner   ossaSingleThreadedEnter(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
179*4e1bc9a0SAchim Leubner #endif /* SA_LL_IBQ_PROTECT */
180*4e1bc9a0SAchim Leubner 
181*4e1bc9a0SAchim Leubner   /* If LL IO request entry avaliable */
182*4e1bc9a0SAchim Leubner   /* Get a free inbound queue entry */
183*4e1bc9a0SAchim Leubner   circularQ = &saRoot->inboundQueue[inq];
184*4e1bc9a0SAchim Leubner   retVal    = mpiMsgFreeGet(circularQ, IOMB_SIZE64, &pMessage);
185*4e1bc9a0SAchim Leubner 
186*4e1bc9a0SAchim Leubner   if (AGSA_RC_FAILURE == retVal)
187*4e1bc9a0SAchim Leubner   {
188*4e1bc9a0SAchim Leubner #ifdef SA_LL_IBQ_PROTECT
189*4e1bc9a0SAchim Leubner     ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
190*4e1bc9a0SAchim Leubner #endif /* SA_LL_IBQ_PROTECT */
191*4e1bc9a0SAchim Leubner     /* if not sending return to free list rare */
192*4e1bc9a0SAchim Leubner     ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
193*4e1bc9a0SAchim Leubner     saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
194*4e1bc9a0SAchim Leubner     pRequest->valid = agFALSE;
195*4e1bc9a0SAchim Leubner     saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
196*4e1bc9a0SAchim Leubner     ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
197*4e1bc9a0SAchim Leubner 
198*4e1bc9a0SAchim Leubner     SA_DBG1(("saSMPStart, error when get free IOMB\n"));
199*4e1bc9a0SAchim Leubner     smTraceFuncExit(hpDBG_VERY_LOUD, 'c', "9a");
200*4e1bc9a0SAchim Leubner     return AGSA_RC_FAILURE;
201*4e1bc9a0SAchim Leubner   }
202*4e1bc9a0SAchim Leubner 
203*4e1bc9a0SAchim Leubner   /* return busy if inbound queue is full */
204*4e1bc9a0SAchim Leubner   if (AGSA_RC_BUSY == retVal)
205*4e1bc9a0SAchim Leubner   {
206*4e1bc9a0SAchim Leubner #ifdef SA_LL_IBQ_PROTECT
207*4e1bc9a0SAchim Leubner     ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
208*4e1bc9a0SAchim Leubner #endif /* SA_LL_IBQ_PROTECT */
209*4e1bc9a0SAchim Leubner     /* if not sending return to free list rare */
210*4e1bc9a0SAchim Leubner     ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
211*4e1bc9a0SAchim Leubner     saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
212*4e1bc9a0SAchim Leubner     pRequest->valid = agFALSE;
213*4e1bc9a0SAchim Leubner     saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
214*4e1bc9a0SAchim Leubner     ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
215*4e1bc9a0SAchim Leubner 
216*4e1bc9a0SAchim Leubner     SA_DBG1(("saSMPStart, no more IOMB\n"));
217*4e1bc9a0SAchim Leubner     smTraceFuncExit(hpDBG_VERY_LOUD, 'd', "9a");
218*4e1bc9a0SAchim Leubner     return AGSA_RC_BUSY;
219*4e1bc9a0SAchim Leubner   }
220*4e1bc9a0SAchim Leubner 
221*4e1bc9a0SAchim Leubner   /* Setup SMP Frame */
222*4e1bc9a0SAchim Leubner   pSMPFrame = (agsaSMPFrame_t *) &(agRequestBody->smpFrame);
223*4e1bc9a0SAchim Leubner 
224*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart:DeviceMapIndex 0x%x portId 0x%x portId 0x%x\n",pDevice->DeviceMapIndex,pPort->portId,pPort->portId));
225*4e1bc9a0SAchim Leubner 
226*4e1bc9a0SAchim Leubner #if defined(SALLSDK_DEBUG)
227*4e1bc9a0SAchim Leubner 
228*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: outFrameBuf  %p\n",pSMPFrame->outFrameBuf));
229*4e1bc9a0SAchim Leubner 
230*4e1bc9a0SAchim Leubner   if(pSMPFrame->outFrameBuf )
231*4e1bc9a0SAchim Leubner   {
232*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 0  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+0) ));
233*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 1  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+1) ));
234*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 2  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+2) ));
235*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 3  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+3) ));
236*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 4  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+4) ));
237*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 5  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+5) ));
238*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 6  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+6) ));
239*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 7  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+7) ));
240*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 8  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+8) ));
241*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 9  0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+9) ));
242*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 11 0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+10) ));
243*4e1bc9a0SAchim Leubner     SA_DBG2(("saSMPStart: outFrameBuf 11 0x%08X\n",*((bit32*)pSMPFrame->outFrameBuf+11) ));
244*4e1bc9a0SAchim Leubner   }
245*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: outFrameAddrUpper32 0x%08X\n",pSMPFrame->outFrameAddrUpper32));
246*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: outFrameAddrLower32 0x%08X\n",pSMPFrame->outFrameAddrLower32));
247*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: outFrameLen         0x%08X\n",pSMPFrame->outFrameLen));
248*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: inFrameAddrUpper32  0x%08X\n",pSMPFrame->inFrameAddrUpper32));
249*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: inFrameAddrLower32  0x%08X\n",pSMPFrame->inFrameAddrLower32));
250*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: inFrameLen          0x%08X\n",pSMPFrame->inFrameLen));
251*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: expectedRespLen     0x%08X\n",pSMPFrame->expectedRespLen));
252*4e1bc9a0SAchim Leubner   SA_DBG2(("saSMPStart: flag                0x%08X\n",pSMPFrame->flag));
253*4e1bc9a0SAchim Leubner #endif /* SALLSDK_DEBUG */
254*4e1bc9a0SAchim Leubner 
255*4e1bc9a0SAchim Leubner   if(smIS_SPC(agRoot))
256*4e1bc9a0SAchim Leubner   // if(1)
257*4e1bc9a0SAchim Leubner   {
258*4e1bc9a0SAchim Leubner     agsaSMPCmd_t payload;
259*4e1bc9a0SAchim Leubner     switch ( agRequestType )
260*4e1bc9a0SAchim Leubner     {
261*4e1bc9a0SAchim Leubner       case AGSA_SMP_INIT_REQ:
262*4e1bc9a0SAchim Leubner       {
263*4e1bc9a0SAchim Leubner         bit32 IR_IP_OV_res_phyId_DPdLen_res = 0;
264*4e1bc9a0SAchim Leubner         /* Prepare the payload of IOMB */
265*4e1bc9a0SAchim Leubner         si_memset(&payload, 0, sizeof(agsaSMPCmd_t));
266*4e1bc9a0SAchim Leubner         OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, tag), pRequest->HTag);
267*4e1bc9a0SAchim Leubner         OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, deviceId), pDevice->DeviceMapIndex);
268*4e1bc9a0SAchim Leubner 
269*4e1bc9a0SAchim Leubner         /* check SMP Response Frame with IR mode */
270*4e1bc9a0SAchim Leubner         /* check if the SMP Response is indirect mode */
271*4e1bc9a0SAchim Leubner         if (0 == pSMPFrame->inFrameLen)
272*4e1bc9a0SAchim Leubner         {
273*4e1bc9a0SAchim Leubner           /* PHY override not support */
274*4e1bc9a0SAchim Leubner           /* Direct Response mode */
275*4e1bc9a0SAchim Leubner           pRequest->IRmode = DIRECT_MODE;
276*4e1bc9a0SAchim Leubner         }
277*4e1bc9a0SAchim Leubner         else
278*4e1bc9a0SAchim Leubner         {
279*4e1bc9a0SAchim Leubner           /* Indirect Response mode */
280*4e1bc9a0SAchim Leubner           pRequest->IRmode = INDIRECT_MODE;
281*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res = 1;
282*4e1bc9a0SAchim Leubner           /* check SMP direct payload mode len */
283*4e1bc9a0SAchim Leubner           if (pSMPFrame->outFrameLen > 32)
284*4e1bc9a0SAchim Leubner           {
285*4e1bc9a0SAchim Leubner #ifdef SA_LL_IBQ_PROTECT
286*4e1bc9a0SAchim Leubner             ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
287*4e1bc9a0SAchim Leubner #endif /* SA_LL_IBQ_PROTECT */
288*4e1bc9a0SAchim Leubner             /* if not sending return to free list rare */
289*4e1bc9a0SAchim Leubner             ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
290*4e1bc9a0SAchim Leubner             saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
291*4e1bc9a0SAchim Leubner             pRequest->valid = agFALSE;
292*4e1bc9a0SAchim Leubner             saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
293*4e1bc9a0SAchim Leubner             ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
294*4e1bc9a0SAchim Leubner             /* can not handle SMP frame length > 32 bytes it if IP=0 and IR=1 */
295*4e1bc9a0SAchim Leubner             SA_DBG1(("saSMPStart, outFrameLen > 32 bytes error.\n"));
296*4e1bc9a0SAchim Leubner             smTraceFuncExit(hpDBG_VERY_LOUD, 'e', "9a");
297*4e1bc9a0SAchim Leubner             return AGSA_RC_FAILURE;
298*4e1bc9a0SAchim Leubner           }
299*4e1bc9a0SAchim Leubner         }
300*4e1bc9a0SAchim Leubner 
301*4e1bc9a0SAchim Leubner         /* check Direct mode or Indirect mode for IP mode */
302*4e1bc9a0SAchim Leubner         if ( (pSMPFrame->outFrameBuf &&
303*4e1bc9a0SAchim Leubner               (pSMPFrame->outFrameLen <= AGSA_MAX_SMPPAYLOAD_VIA_SFO)) ||
304*4e1bc9a0SAchim Leubner              ((pSMPFrame->outFrameBuf == agNULL) &&
305*4e1bc9a0SAchim Leubner               (pSMPFrame->outFrameLen == 0) )
306*4e1bc9a0SAchim Leubner            )
307*4e1bc9a0SAchim Leubner         {
308*4e1bc9a0SAchim Leubner           SA_DBG4(("saSMPStart: DIRECT Request SMP\n"));
309*4e1bc9a0SAchim Leubner 
310*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res = (DIRECT_MODE << 1) | IR_IP_OV_res_phyId_DPdLen_res;
311*4e1bc9a0SAchim Leubner 
312*4e1bc9a0SAchim Leubner           /* Direct payload length */
313*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res |= (((pSMPFrame->outFrameLen) & 0xff) << SHIFT16);
314*4e1bc9a0SAchim Leubner 
315*4e1bc9a0SAchim Leubner           /* copy payload - upto 48 bytes */
316*4e1bc9a0SAchim Leubner           si_memcpy(&(payload.SMPCmd[0]),pSMPFrame->outFrameBuf,pSMPFrame->outFrameLen);
317*4e1bc9a0SAchim Leubner           for ( i = 0; i < pSMPFrame->outFrameLen / sizeof(bit32)+1; i ++ )
318*4e1bc9a0SAchim Leubner           {
319*4e1bc9a0SAchim Leubner             SA_DBG4(("saSMPStart: payload.SMPCmd[%d] %x\n", i, payload.SMPCmd[i]));
320*4e1bc9a0SAchim Leubner           }
321*4e1bc9a0SAchim Leubner         }
322*4e1bc9a0SAchim Leubner         else
323*4e1bc9a0SAchim Leubner         {
324*4e1bc9a0SAchim Leubner           SA_DBG4(("saSMPStart: INDIRECT Request SMP\n"));
325*4e1bc9a0SAchim Leubner           /* use physical address */
326*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res = (INDIRECT_MODE << 1) | IR_IP_OV_res_phyId_DPdLen_res;
327*4e1bc9a0SAchim Leubner 
328*4e1bc9a0SAchim Leubner           /* Direct payload length = 0 */
329*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res = IR_IP_OV_res_phyId_DPdLen_res & 0xff00ffff;
330*4e1bc9a0SAchim Leubner 
331*4e1bc9a0SAchim Leubner           /* payload */
332*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, SMPCmd[4]), (pSMPFrame->outFrameAddrLower32));
333*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, SMPCmd[5]), (pSMPFrame->outFrameAddrUpper32));
334*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, SMPCmd[6]), (pSMPFrame->outFrameLen));
335*4e1bc9a0SAchim Leubner         }
336*4e1bc9a0SAchim Leubner         /* Write IR_IP_OV_res_phyId_DPdLen_res field in the payload*/
337*4e1bc9a0SAchim Leubner         OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, IR_IP_OV_res_phyId_DPdLen_res), IR_IP_OV_res_phyId_DPdLen_res);
338*4e1bc9a0SAchim Leubner 
339*4e1bc9a0SAchim Leubner         /* check IR bit */
340*4e1bc9a0SAchim Leubner         if (IR_IP_OV_res_phyId_DPdLen_res & INDIRECT_MODE)
341*4e1bc9a0SAchim Leubner         {
342*4e1bc9a0SAchim Leubner           /* setup indirect response frame address */
343*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, SMPCmd[8]), (pSMPFrame->inFrameAddrLower32));
344*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, SMPCmd[9]), (pSMPFrame->inFrameAddrUpper32));
345*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPCmd_t, SMPCmd[10]), (pSMPFrame->inFrameLen));
346*4e1bc9a0SAchim Leubner         }
347*4e1bc9a0SAchim Leubner 
348*4e1bc9a0SAchim Leubner         /* Build IOMB command and send it to SPC */
349*4e1bc9a0SAchim Leubner         payload_ptr = (bit8 *)&payload;
350*4e1bc9a0SAchim Leubner         ret = mpiSMPCmd(agRoot, pMessage, OPC_INB_SMP_REQUEST, (agsaSMPCmd_t *)payload_ptr, inq, outq);
351*4e1bc9a0SAchim Leubner 
352*4e1bc9a0SAchim Leubner   #ifdef SA_LL_IBQ_PROTECT
353*4e1bc9a0SAchim Leubner         ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
354*4e1bc9a0SAchim Leubner   #endif /* SA_LL_IBQ_PROTECT */
355*4e1bc9a0SAchim Leubner 
356*4e1bc9a0SAchim Leubner         break;
357*4e1bc9a0SAchim Leubner       }
358*4e1bc9a0SAchim Leubner       default:
359*4e1bc9a0SAchim Leubner       {
360*4e1bc9a0SAchim Leubner         SA_DBG1(("saSMPStart: SPC unknown agRequestType  %x\n",agRequestType));
361*4e1bc9a0SAchim Leubner         break;
362*4e1bc9a0SAchim Leubner       }
363*4e1bc9a0SAchim Leubner     }
364*4e1bc9a0SAchim Leubner 
365*4e1bc9a0SAchim Leubner #ifdef SALL_API_TEST
366*4e1bc9a0SAchim Leubner   if (ret == AGSA_RC_SUCCESS)
367*4e1bc9a0SAchim Leubner     saRoot->LLCounters.IOCounter.numSMPStarted++;
368*4e1bc9a0SAchim Leubner #endif
369*4e1bc9a0SAchim Leubner   }
370*4e1bc9a0SAchim Leubner   else /* IOMB is different for SPCV SMP */
371*4e1bc9a0SAchim Leubner   {
372*4e1bc9a0SAchim Leubner    agsaSMPCmd_V_t vpayload;
373*4e1bc9a0SAchim Leubner 
374*4e1bc9a0SAchim Leubner     switch ( agRequestType )
375*4e1bc9a0SAchim Leubner     {
376*4e1bc9a0SAchim Leubner       case AGSA_SMP_INIT_REQ:
377*4e1bc9a0SAchim Leubner       {
378*4e1bc9a0SAchim Leubner         bit32 IR_IP_OV_res_phyId_DPdLen_res = 0;
379*4e1bc9a0SAchim Leubner         /* Prepare the payload of IOMB */
380*4e1bc9a0SAchim Leubner         si_memset(&vpayload, 0, sizeof(agsaSMPCmd_V_t));
381*4e1bc9a0SAchim Leubner         OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, tag), pRequest->HTag);
382*4e1bc9a0SAchim Leubner         OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, deviceId), pDevice->DeviceMapIndex);
383*4e1bc9a0SAchim Leubner 
384*4e1bc9a0SAchim Leubner         /* Request header must be valid regardless of IP bit */
385*4e1bc9a0SAchim Leubner         OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,SMPHDR ), *((bit32*)pSMPFrame->outFrameBuf+0) );
386*4e1bc9a0SAchim Leubner 
387*4e1bc9a0SAchim Leubner         /* check SMP Response Frame with IR mode */
388*4e1bc9a0SAchim Leubner         /* check if the SMP Response is indirect mode */
389*4e1bc9a0SAchim Leubner         // smpFrameFlagDirectResponse smpFrameFlagDirectPayload
390*4e1bc9a0SAchim Leubner         if ( 0 == pSMPFrame->flag && pSMPFrame->outFrameBuf )
391*4e1bc9a0SAchim Leubner         {
392*4e1bc9a0SAchim Leubner           /* PHY override not support */
393*4e1bc9a0SAchim Leubner           /* Direct Response mode */
394*4e1bc9a0SAchim Leubner           pRequest->IRmode = DIRECT_MODE;
395*4e1bc9a0SAchim Leubner           SA_DBG2(("saSMPStart:V DIRECT Request SMP\n"));
396*4e1bc9a0SAchim Leubner 
397*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res = (DIRECT_MODE << 1) | IR_IP_OV_res_phyId_DPdLen_res;
398*4e1bc9a0SAchim Leubner 
399*4e1bc9a0SAchim Leubner           /* Direct payload length */
400*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res |= (((pSMPFrame->outFrameLen) & 0xff) << SHIFT16);
401*4e1bc9a0SAchim Leubner           /* Write IR_IP_OV_res_phyId_DPdLen_res field in the payload*/
402*4e1bc9a0SAchim Leubner           /* fatal error if missing */
403*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, IR_IP_OV_res_phyId_DPdLen_res), IR_IP_OV_res_phyId_DPdLen_res);
404*4e1bc9a0SAchim Leubner           /* fatal error if missing */
405*4e1bc9a0SAchim Leubner 
406*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,SMP3_0 ), *((bit32*)pSMPFrame->outFrameBuf+1) );
407*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,SMP7_4 ), *((bit32*)pSMPFrame->outFrameBuf+2) );
408*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,SMP11_8), *((bit32*)pSMPFrame->outFrameBuf+3) );
409*4e1bc9a0SAchim Leubner 
410*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirL_SMPRF15_12 ),     *((bit32*)pSMPFrame->outFrameBuf+4) );
411*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirH_or_SMPRF19_16 ),  *((bit32*)pSMPFrame->outFrameBuf+5) );
412*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirLen_or_SMPRF23_20 ),*((bit32*)pSMPFrame->outFrameBuf+6) );
413*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,R_or_SMPRF27_24),        *((bit32*)pSMPFrame->outFrameBuf+7) );
414*4e1bc9a0SAchim Leubner 
415*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,ISRAL_or_SMPRF31_28 ),   *((bit32*)pSMPFrame->outFrameBuf+8) );
416*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,ISRAH_or_SMPRF35_32 ),   *((bit32*)pSMPFrame->outFrameBuf+9) );
417*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,ISRL_or_SMPRF39_36 ),    *((bit32*)pSMPFrame->outFrameBuf+10) );
418*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,R_or_SMPRF43_40 ),       *((bit32*)pSMPFrame->outFrameBuf+11) );
419*4e1bc9a0SAchim Leubner 
420*4e1bc9a0SAchim Leubner         }
421*4e1bc9a0SAchim Leubner         else if (smpFrameFlagIndirectResponse & pSMPFrame->flag && smpFrameFlagIndirectPayload & pSMPFrame->flag) /* */
422*4e1bc9a0SAchim Leubner         {
423*4e1bc9a0SAchim Leubner           /* IR IP */
424*4e1bc9a0SAchim Leubner           SA_DBG2(("saSMPStart:V smpFrameFlagIndirectResponse smpFrameFlagIndirectPayload SMP\n"));
425*4e1bc9a0SAchim Leubner 
426*4e1bc9a0SAchim Leubner           pRequest->IRmode = INDIRECT_MODE;
427*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res = 3;
428*4e1bc9a0SAchim Leubner 
429*4e1bc9a0SAchim Leubner           /* Indirect payload mode */
430*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirL_SMPRF15_12 ), pSMPFrame->outFrameAddrLower32);
431*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirH_or_SMPRF19_16 ), pSMPFrame->outFrameAddrUpper32);
432*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirLen_or_SMPRF23_20 ), pSMPFrame->outFrameLen);
433*4e1bc9a0SAchim Leubner           /* Indirect Response mode */
434*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, ISRAL_or_SMPRF31_28 ), (pSMPFrame->inFrameAddrLower32));
435*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, ISRAH_or_SMPRF35_32 ), (pSMPFrame->inFrameAddrUpper32));
436*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, ISRL_or_SMPRF39_36 ), (pSMPFrame->inFrameLen));
437*4e1bc9a0SAchim Leubner         }
438*4e1bc9a0SAchim Leubner         else if (smpFrameFlagIndirectPayload & pSMPFrame->flag ) /* */
439*4e1bc9a0SAchim Leubner         {
440*4e1bc9a0SAchim Leubner           /* IP */
441*4e1bc9a0SAchim Leubner           SA_DBG2(("saSMPStart:V  smpFrameFlagIndirectPayload SMP\n"));
442*4e1bc9a0SAchim Leubner           pRequest->IRmode = DIRECT_MODE;
443*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res = 2;
444*4e1bc9a0SAchim Leubner 
445*4e1bc9a0SAchim Leubner           /* Indirect payload mode */
446*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirL_SMPRF15_12 ), pSMPFrame->outFrameAddrLower32);
447*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirH_or_SMPRF19_16 ), pSMPFrame->outFrameAddrUpper32);
448*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirLen_or_SMPRF23_20 ), pSMPFrame->outFrameLen);
449*4e1bc9a0SAchim Leubner         }
450*4e1bc9a0SAchim Leubner         else if (smpFrameFlagIndirectResponse & pSMPFrame->flag ) /* */
451*4e1bc9a0SAchim Leubner         {
452*4e1bc9a0SAchim Leubner           /* check IR bit */
453*4e1bc9a0SAchim Leubner           /* Indirect Response mode */
454*4e1bc9a0SAchim Leubner           pRequest->IRmode = INDIRECT_MODE;
455*4e1bc9a0SAchim Leubner           SA_DBG2(("saSMPStart:V smpFrameFlagIndirectResponse SMP\n"));
456*4e1bc9a0SAchim Leubner           /* use physical address */
457*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res = 1;
458*4e1bc9a0SAchim Leubner           /* Direct payload length */
459*4e1bc9a0SAchim Leubner           IR_IP_OV_res_phyId_DPdLen_res |= (((pSMPFrame->outFrameLen) & 0xff) << SHIFT16);
460*4e1bc9a0SAchim Leubner 
461*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,SMP3_0 ), *((bit32*)pSMPFrame->outFrameBuf+1) );
462*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,SMP7_4 ), *((bit32*)pSMPFrame->outFrameBuf+2) );
463*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,SMP11_8), *((bit32*)pSMPFrame->outFrameBuf+3) );
464*4e1bc9a0SAchim Leubner 
465*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirL_SMPRF15_12 ),     *((bit32*)pSMPFrame->outFrameBuf+4) );
466*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirH_or_SMPRF19_16 ),  *((bit32*)pSMPFrame->outFrameBuf+5) );
467*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,IndirLen_or_SMPRF23_20 ),*((bit32*)pSMPFrame->outFrameBuf+6) );
468*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t,R_or_SMPRF27_24),        *((bit32*)pSMPFrame->outFrameBuf+7) );
469*4e1bc9a0SAchim Leubner 
470*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, ISRAL_or_SMPRF31_28 ), (pSMPFrame->inFrameAddrLower32));
471*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, ISRAH_or_SMPRF35_32 ), (pSMPFrame->inFrameAddrUpper32));
472*4e1bc9a0SAchim Leubner           OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, ISRL_or_SMPRF39_36 ), (pSMPFrame->inFrameLen));
473*4e1bc9a0SAchim Leubner         }
474*4e1bc9a0SAchim Leubner         IR_IP_OV_res_phyId_DPdLen_res |= (pSMPFrame->flag & 3);
475*4e1bc9a0SAchim Leubner         /* fatal error if missing */
476*4e1bc9a0SAchim Leubner         OSSA_WRITE_LE_32(agRoot, &vpayload, OSSA_OFFSET_OF(agsaSMPCmd_V_t, IR_IP_OV_res_phyId_DPdLen_res), IR_IP_OV_res_phyId_DPdLen_res);
477*4e1bc9a0SAchim Leubner         /* fatal error if missing */
478*4e1bc9a0SAchim Leubner       }
479*4e1bc9a0SAchim Leubner       /* Build IOMB command and send it to SPCv */
480*4e1bc9a0SAchim Leubner       payload_ptr = (bit8 *)&vpayload;
481*4e1bc9a0SAchim Leubner       ret = mpiSMPCmd(agRoot, pMessage, OPC_INB_SMP_REQUEST, (agsaSMPCmd_t *)payload_ptr, inq, outq);
482*4e1bc9a0SAchim Leubner 
483*4e1bc9a0SAchim Leubner #ifdef SA_LL_IBQ_PROTECT
484*4e1bc9a0SAchim Leubner       ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
485*4e1bc9a0SAchim Leubner #endif /* SA_LL_IBQ_PROTECT */
486*4e1bc9a0SAchim Leubner 
487*4e1bc9a0SAchim Leubner       break;
488*4e1bc9a0SAchim Leubner       default:
489*4e1bc9a0SAchim Leubner       {
490*4e1bc9a0SAchim Leubner         SA_DBG1(("saSMPStart: SPCv unknown agRequestType  %x\n",agRequestType));
491*4e1bc9a0SAchim Leubner         break;
492*4e1bc9a0SAchim Leubner       }
493*4e1bc9a0SAchim Leubner     }
494*4e1bc9a0SAchim Leubner   }
495*4e1bc9a0SAchim Leubner 
496*4e1bc9a0SAchim Leubner   smTraceFuncExit(hpDBG_VERY_LOUD, 'f', "9a");
497*4e1bc9a0SAchim Leubner 
498*4e1bc9a0SAchim Leubner   /* return */
499*4e1bc9a0SAchim Leubner   return ret;
500*4e1bc9a0SAchim Leubner }
501*4e1bc9a0SAchim Leubner 
502*4e1bc9a0SAchim Leubner /******************************************************************************/
503*4e1bc9a0SAchim Leubner /*! \brief Abort SMP request
504*4e1bc9a0SAchim Leubner  *
505*4e1bc9a0SAchim Leubner  *  Abort SMP request
506*4e1bc9a0SAchim Leubner  *
507*4e1bc9a0SAchim Leubner  *  \param agRoot handles for this instance of SAS/SATA hardware
508*4e1bc9a0SAchim Leubner  *  \param queueNum
509*4e1bc9a0SAchim Leubner  *  \param agIORequest
510*4e1bc9a0SAchim Leubner  *
511*4e1bc9a0SAchim Leubner  *  \return If request is aborted successfully
512*4e1bc9a0SAchim Leubner  *          - \e AGSA_RC_SUCCESS request is aborted successfully
513*4e1bc9a0SAchim Leubner  *          - \e AGSA_RC_FAILURE request is not aborted successfully
514*4e1bc9a0SAchim Leubner  */
515*4e1bc9a0SAchim Leubner /*******************************************************************************/
saSMPAbort(agsaRoot_t * agRoot,agsaIORequest_t * agIORequest,bit32 queueNum,agsaDevHandle_t * agDevHandle,bit32 flag,void * abortParam,ossaGenericAbortCB_t agCB)516*4e1bc9a0SAchim Leubner GLOBAL bit32 saSMPAbort(
517*4e1bc9a0SAchim Leubner   agsaRoot_t           *agRoot,
518*4e1bc9a0SAchim Leubner   agsaIORequest_t      *agIORequest,
519*4e1bc9a0SAchim Leubner   bit32                 queueNum,
520*4e1bc9a0SAchim Leubner   agsaDevHandle_t      *agDevHandle,
521*4e1bc9a0SAchim Leubner   bit32                 flag,
522*4e1bc9a0SAchim Leubner   void                 *abortParam,
523*4e1bc9a0SAchim Leubner   ossaGenericAbortCB_t  agCB
524*4e1bc9a0SAchim Leubner   )
525*4e1bc9a0SAchim Leubner {
526*4e1bc9a0SAchim Leubner   bit32 ret = AGSA_RC_SUCCESS;
527*4e1bc9a0SAchim Leubner   agsaLLRoot_t        *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
528*4e1bc9a0SAchim Leubner   agsaIORequestDesc_t *pRequest;
529*4e1bc9a0SAchim Leubner   agsaIORequestDesc_t *pRequestABT = NULL;
530*4e1bc9a0SAchim Leubner   agsaIORequest_t     *agIOToBeAborted;
531*4e1bc9a0SAchim Leubner   agsaDeviceDesc_t    *pDevice;
532*4e1bc9a0SAchim Leubner   agsaSMPAbortCmd_t   payload;
533*4e1bc9a0SAchim Leubner   bit32               using_reserved = agFALSE;
534*4e1bc9a0SAchim Leubner 
535*4e1bc9a0SAchim Leubner   smTraceFuncEnter(hpDBG_VERY_LOUD,"9b");
536*4e1bc9a0SAchim Leubner 
537*4e1bc9a0SAchim Leubner   /* sanity check */
538*4e1bc9a0SAchim Leubner   SA_ASSERT((agNULL != agRoot), "");
539*4e1bc9a0SAchim Leubner   SA_ASSERT((agNULL != agIORequest), "");
540*4e1bc9a0SAchim Leubner   SA_ASSERT((agNULL != agDevHandle), "");
541*4e1bc9a0SAchim Leubner 
542*4e1bc9a0SAchim Leubner   SA_DBG3(("saSMPAbort: Aborting request %p\n", agIORequest));
543*4e1bc9a0SAchim Leubner 
544*4e1bc9a0SAchim Leubner   if( ABORT_SINGLE == (flag & ABORT_MASK) )
545*4e1bc9a0SAchim Leubner   {
546*4e1bc9a0SAchim Leubner     agIOToBeAborted = (agsaIORequest_t *)abortParam;
547*4e1bc9a0SAchim Leubner     /* Get LL IORequest entry for saSMPAbort() */
548*4e1bc9a0SAchim Leubner     pRequestABT = (agsaIORequestDesc_t *) (agIOToBeAborted->sdkData);
549*4e1bc9a0SAchim Leubner     if (agNULL == pRequestABT)
550*4e1bc9a0SAchim Leubner     {
551*4e1bc9a0SAchim Leubner       /* The IO to Be Abort is no longer exist - can not Abort */
552*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPAbort: pRequestABT AGSA_RC_FAILURE\n"));
553*4e1bc9a0SAchim Leubner       smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "9b");
554*4e1bc9a0SAchim Leubner       return AGSA_RC_FAILURE;
555*4e1bc9a0SAchim Leubner     }
556*4e1bc9a0SAchim Leubner 
557*4e1bc9a0SAchim Leubner     /* Find the device the request Abort to */
558*4e1bc9a0SAchim Leubner     pDevice = pRequestABT->pDevice;
559*4e1bc9a0SAchim Leubner 
560*4e1bc9a0SAchim Leubner     if (agNULL == pDevice)
561*4e1bc9a0SAchim Leubner     {
562*4e1bc9a0SAchim Leubner       /* no deviceID - can not build IOMB */
563*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPAbort: pDevice AGSA_RC_FAILURE\n"));
564*4e1bc9a0SAchim Leubner       smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "9b");
565*4e1bc9a0SAchim Leubner       return AGSA_RC_FAILURE;
566*4e1bc9a0SAchim Leubner     }
567*4e1bc9a0SAchim Leubner   }
568*4e1bc9a0SAchim Leubner   else
569*4e1bc9a0SAchim Leubner   {
570*4e1bc9a0SAchim Leubner     if (ABORT_ALL == (flag & ABORT_MASK))
571*4e1bc9a0SAchim Leubner     {
572*4e1bc9a0SAchim Leubner       /* abort All with Device or Port */
573*4e1bc9a0SAchim Leubner       /* Find the outgoing port for the device */
574*4e1bc9a0SAchim Leubner       pDevice = (agsaDeviceDesc_t *) (agDevHandle->sdkData);
575*4e1bc9a0SAchim Leubner       if (agNULL == pDevice)
576*4e1bc9a0SAchim Leubner       {
577*4e1bc9a0SAchim Leubner         /* no deviceID - can not build IOMB */
578*4e1bc9a0SAchim Leubner         SA_DBG1(("saSMPAbort:ABORT_ALL pDevice AGSA_RC_FAILURE\n"));
579*4e1bc9a0SAchim Leubner         smTraceFuncExit(hpDBG_VERY_LOUD, 'c', "9b");
580*4e1bc9a0SAchim Leubner         return AGSA_RC_FAILURE;
581*4e1bc9a0SAchim Leubner       }
582*4e1bc9a0SAchim Leubner     }
583*4e1bc9a0SAchim Leubner     else
584*4e1bc9a0SAchim Leubner     {
585*4e1bc9a0SAchim Leubner       /* only support 00 and 01 for flag */
586*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPAbort:flag  AGSA_RC_FAILURE\n"));
587*4e1bc9a0SAchim Leubner       smTraceFuncExit(hpDBG_VERY_LOUD, 'd', "9b");
588*4e1bc9a0SAchim Leubner       return AGSA_RC_FAILURE;
589*4e1bc9a0SAchim Leubner     }
590*4e1bc9a0SAchim Leubner   }
591*4e1bc9a0SAchim Leubner 
592*4e1bc9a0SAchim Leubner   /* Get LL IORequest entry */
593*4e1bc9a0SAchim Leubner   ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
594*4e1bc9a0SAchim Leubner   pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));
595*4e1bc9a0SAchim Leubner 
596*4e1bc9a0SAchim Leubner   /* If no LL IO request entry available */
597*4e1bc9a0SAchim Leubner   if ( agNULL == pRequest )
598*4e1bc9a0SAchim Leubner   {
599*4e1bc9a0SAchim Leubner     pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests)); /**/
600*4e1bc9a0SAchim Leubner     /* If no LL Control request entry available */
601*4e1bc9a0SAchim Leubner     if(agNULL != pRequest)
602*4e1bc9a0SAchim Leubner     {
603*4e1bc9a0SAchim Leubner       using_reserved = agTRUE;
604*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPAbort, using saRoot->freeReservedRequests\n"));
605*4e1bc9a0SAchim Leubner     }
606*4e1bc9a0SAchim Leubner     else
607*4e1bc9a0SAchim Leubner     {
608*4e1bc9a0SAchim Leubner       ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
609*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPAbort, No request from free list Not using saRoot->freeReservedRequests\n"));
610*4e1bc9a0SAchim Leubner       smTraceFuncExit(hpDBG_VERY_LOUD, 'e', "9b");
611*4e1bc9a0SAchim Leubner       return AGSA_RC_BUSY;
612*4e1bc9a0SAchim Leubner     }
613*4e1bc9a0SAchim Leubner   }
614*4e1bc9a0SAchim Leubner 
615*4e1bc9a0SAchim Leubner   /* If free IOMB avaliable */
616*4e1bc9a0SAchim Leubner   /* Remove the request from free list */
617*4e1bc9a0SAchim Leubner   if( using_reserved )
618*4e1bc9a0SAchim Leubner   {
619*4e1bc9a0SAchim Leubner     saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
620*4e1bc9a0SAchim Leubner   }
621*4e1bc9a0SAchim Leubner   else
622*4e1bc9a0SAchim Leubner   {
623*4e1bc9a0SAchim Leubner     saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
624*4e1bc9a0SAchim Leubner   }
625*4e1bc9a0SAchim Leubner 
626*4e1bc9a0SAchim Leubner   /* Add the request to the pendingSMPRequests list of the device */
627*4e1bc9a0SAchim Leubner   saLlistIOAdd(&(pDevice->pendingIORequests), &(pRequest->linkNode));
628*4e1bc9a0SAchim Leubner   SA_ASSERT((!pRequest->valid), "The pRequest is in use");
629*4e1bc9a0SAchim Leubner   pRequest->valid             = agTRUE;
630*4e1bc9a0SAchim Leubner   ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
631*4e1bc9a0SAchim Leubner   /* set up pRequest */
632*4e1bc9a0SAchim Leubner   pRequest->pIORequestContext = agIORequest;
633*4e1bc9a0SAchim Leubner   pRequest->requestType       = AGSA_SMP_REQTYPE;
634*4e1bc9a0SAchim Leubner   pRequest->completionCB = (void*)agCB;
635*4e1bc9a0SAchim Leubner   pRequest->pDevice           = pDevice;
636*4e1bc9a0SAchim Leubner   pRequest->startTick         = saRoot->timeTick;
637*4e1bc9a0SAchim Leubner 
638*4e1bc9a0SAchim Leubner   /* Set request to the sdkData of agIORequest */
639*4e1bc9a0SAchim Leubner   agIORequest->sdkData        = pRequest;
640*4e1bc9a0SAchim Leubner 
641*4e1bc9a0SAchim Leubner   /* save tag to IOMap */
642*4e1bc9a0SAchim Leubner   saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
643*4e1bc9a0SAchim Leubner   saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
644*4e1bc9a0SAchim Leubner 
645*4e1bc9a0SAchim Leubner   /* setup payload */
646*4e1bc9a0SAchim Leubner   OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPAbortCmd_t, tag), pRequest->HTag);
647*4e1bc9a0SAchim Leubner 
648*4e1bc9a0SAchim Leubner   if( ABORT_SINGLE == (flag & ABORT_MASK) )
649*4e1bc9a0SAchim Leubner   {
650*4e1bc9a0SAchim Leubner     if (agNULL == pRequestABT)
651*4e1bc9a0SAchim Leubner     {
652*4e1bc9a0SAchim Leubner       /* remove the request from IOMap */
653*4e1bc9a0SAchim Leubner       saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
654*4e1bc9a0SAchim Leubner       saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
655*4e1bc9a0SAchim Leubner       saRoot->IOMap[pRequest->HTag].agContext = agNULL;
656*4e1bc9a0SAchim Leubner       /* Delete the request from the pendingSMPRequests */
657*4e1bc9a0SAchim Leubner       ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
658*4e1bc9a0SAchim Leubner       saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
659*4e1bc9a0SAchim Leubner       /* return the request to free pool */
660*4e1bc9a0SAchim Leubner       if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT)
661*4e1bc9a0SAchim Leubner       {
662*4e1bc9a0SAchim Leubner         SA_DBG1(("saSMPAbort: saving pRequest (%p) for later use\n", pRequest));
663*4e1bc9a0SAchim Leubner         saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
664*4e1bc9a0SAchim Leubner       }
665*4e1bc9a0SAchim Leubner       else
666*4e1bc9a0SAchim Leubner       {
667*4e1bc9a0SAchim Leubner         /* return the request to free pool */
668*4e1bc9a0SAchim Leubner         saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
669*4e1bc9a0SAchim Leubner       }
670*4e1bc9a0SAchim Leubner       ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
671*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPAbort, agNULL == pRequestABT\n"));
672*4e1bc9a0SAchim Leubner       /* The IO to Be Abort is no longer exist - can not Abort */
673*4e1bc9a0SAchim Leubner       smTraceFuncExit(hpDBG_VERY_LOUD, 'f', "9b");
674*4e1bc9a0SAchim Leubner       return AGSA_RC_FAILURE;
675*4e1bc9a0SAchim Leubner     }
676*4e1bc9a0SAchim Leubner     OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPAbortCmd_t, HTagAbort), pRequestABT->HTag);
677*4e1bc9a0SAchim Leubner   }
678*4e1bc9a0SAchim Leubner   else
679*4e1bc9a0SAchim Leubner   {
680*4e1bc9a0SAchim Leubner     /* abort all */
681*4e1bc9a0SAchim Leubner     OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPAbortCmd_t, HTagAbort), 0);
682*4e1bc9a0SAchim Leubner   }
683*4e1bc9a0SAchim Leubner   OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPAbortCmd_t, deviceId), pDevice->DeviceMapIndex);
684*4e1bc9a0SAchim Leubner   OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSMPAbortCmd_t, Scp), flag);
685*4e1bc9a0SAchim Leubner 
686*4e1bc9a0SAchim Leubner   SA_DBG1(("saSMPAbort, HTag 0x%x HTagABT 0x%x deviceId 0x%x\n", payload.tag, payload.HTagAbort, payload.deviceId));
687*4e1bc9a0SAchim Leubner 
688*4e1bc9a0SAchim Leubner   /* build IOMB command and send to SPC */
689*4e1bc9a0SAchim Leubner   ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SMP_ABORT, IOMB_SIZE64, queueNum);
690*4e1bc9a0SAchim Leubner   if (AGSA_RC_SUCCESS != ret)
691*4e1bc9a0SAchim Leubner   {
692*4e1bc9a0SAchim Leubner     /* remove the request from IOMap */
693*4e1bc9a0SAchim Leubner     saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
694*4e1bc9a0SAchim Leubner     saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
695*4e1bc9a0SAchim Leubner     saRoot->IOMap[pRequest->HTag].agContext = agNULL;
696*4e1bc9a0SAchim Leubner     /* Delete the request from the pendingSMPRequests */
697*4e1bc9a0SAchim Leubner     ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
698*4e1bc9a0SAchim Leubner     saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
699*4e1bc9a0SAchim Leubner     /* return the request to free pool */
700*4e1bc9a0SAchim Leubner     if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT)
701*4e1bc9a0SAchim Leubner     {
702*4e1bc9a0SAchim Leubner       SA_DBG1(("saSMPAbort: saving pRequest (%p) for later use\n", pRequest));
703*4e1bc9a0SAchim Leubner       saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
704*4e1bc9a0SAchim Leubner     }
705*4e1bc9a0SAchim Leubner     else
706*4e1bc9a0SAchim Leubner     {
707*4e1bc9a0SAchim Leubner       /* return the request to free pool */
708*4e1bc9a0SAchim Leubner       saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
709*4e1bc9a0SAchim Leubner     }
710*4e1bc9a0SAchim Leubner     ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
711*4e1bc9a0SAchim Leubner     SA_DBG1(("saSMPAbort, sending IOMB failed\n" ));
712*4e1bc9a0SAchim Leubner   }
713*4e1bc9a0SAchim Leubner #ifdef SALL_API_TEST
714*4e1bc9a0SAchim Leubner   else
715*4e1bc9a0SAchim Leubner   {
716*4e1bc9a0SAchim Leubner     saRoot->LLCounters.IOCounter.numSMPAborted++;
717*4e1bc9a0SAchim Leubner   }
718*4e1bc9a0SAchim Leubner #endif
719*4e1bc9a0SAchim Leubner 
720*4e1bc9a0SAchim Leubner   smTraceFuncExit(hpDBG_VERY_LOUD, 'g', "9b");
721*4e1bc9a0SAchim Leubner 
722*4e1bc9a0SAchim Leubner   return ret;
723*4e1bc9a0SAchim Leubner }
724*4e1bc9a0SAchim Leubner 
725*4e1bc9a0SAchim Leubner 
726*4e1bc9a0SAchim Leubner 
727