1 /*******************************************************************************
2 *Copyright (c) 2014 PMC-Sierra, Inc. All rights reserved.
3 *
4 *Redistribution and use in source and binary forms, with or without modification, are permitted provided
5 *that the following conditions are met:
6 *1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
7 *following disclaimer.
8 *2. Redistributions in binary form must reproduce the above copyright notice,
9 *this list of conditions and the following disclaimer in the documentation and/or other materials provided
10 *with the distribution.
11 *
12 *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
13 *WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 *FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
15 *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16 *NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
17 *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18 *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19 *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
20
21 ********************************************************************************/
22 #include <sys/cdefs.h>
23 #include <dev/pms/config.h>
24
25 #include <dev/pms/freebsd/driver/common/osenv.h>
26 #include <dev/pms/freebsd/driver/common/ostypes.h>
27 #include <dev/pms/freebsd/driver/common/osdebug.h>
28
29 #include <dev/pms/RefTisa/tisa/api/titypes.h>
30
31 #include <dev/pms/RefTisa/sallsdk/api/sa.h>
32 #include <dev/pms/RefTisa/sallsdk/api/saapi.h>
33 #include <dev/pms/RefTisa/sallsdk/api/saosapi.h>
34
35 #include <dev/pms/RefTisa/sat/api/sm.h>
36 #include <dev/pms/RefTisa/sat/api/smapi.h>
37 #include <dev/pms/RefTisa/sat/api/tdsmapi.h>
38
39 #include <dev/pms/RefTisa/sat/src/smdefs.h>
40 #include <dev/pms/RefTisa/sat/src/smproto.h>
41 #include <dev/pms/RefTisa/sat/src/smtypes.h>
42
43 #ifdef SM_DEBUG
44 bit32 gSMDebugLevel = 1;
45 #endif
46 smRoot_t *gsmRoot = agNULL;
47
48 /* start smapi defined APIS */
49 osGLOBAL void
smGetRequirements(smRoot_t * smRoot,smSwConfig_t * swConfig,smMemoryRequirement_t * memoryRequirement,bit32 * usecsPerTick,bit32 * maxNumLocks)50 smGetRequirements(
51 smRoot_t *smRoot,
52 smSwConfig_t *swConfig,
53 smMemoryRequirement_t *memoryRequirement,
54 bit32 *usecsPerTick,
55 bit32 *maxNumLocks
56 )
57 {
58 bit32 memoryReqCount = 0;
59 bit32 i;
60 bit32 max_dev = SM_MAX_DEV;
61 char *buffer;
62 bit32 buffLen;
63 bit32 lenRecv = 0;
64 static char tmpBuffer[DEFAULT_KEY_BUFFER_SIZE];
65 char *pLastUsedChar = agNULL;
66 char globalStr[] = "Global";
67 char iniParmsStr[] = "InitiatorParms";
68 SM_DBG2(("smGetRequirements: start\n"));
69
70 /* sanity check */
71 SM_ASSERT((agNULL != swConfig), "");
72 SM_ASSERT((agNULL != memoryRequirement), "");
73 SM_ASSERT((agNULL != usecsPerTick), "");
74 SM_ASSERT((agNULL != maxNumLocks), "");
75
76 /* memory requirement for smRoot, CACHE memory */
77 memoryRequirement->smMemory[SM_ROOT_MEM_INDEX].singleElementLength = sizeof(smIntRoot_t);
78 memoryRequirement->smMemory[SM_ROOT_MEM_INDEX].numElements = 1;
79 memoryRequirement->smMemory[SM_ROOT_MEM_INDEX].totalLength =
80 (memoryRequirement->smMemory[SM_ROOT_MEM_INDEX].singleElementLength) * (memoryRequirement->smMemory[SM_ROOT_MEM_INDEX].numElements);
81 memoryRequirement->smMemory[SM_ROOT_MEM_INDEX].alignment = 4;
82 memoryRequirement->smMemory[SM_ROOT_MEM_INDEX].type = SM_CACHED_MEM;
83 memoryReqCount++;
84
85 /* reading the configurable parameter of MaxTargets */
86 buffer = tmpBuffer;
87 buffLen = sizeof(tmpBuffer);
88 sm_memset(buffer, 0, buffLen);
89 lenRecv = 0;
90 if ((tdsmGetTransportParam(
91 smRoot,
92 globalStr,
93 iniParmsStr,
94 agNULL,
95 agNULL,
96 agNULL,
97 agNULL,
98 "MaxTargets",
99 buffer,
100 buffLen,
101 &lenRecv
102 ) == SM_RC_SUCCESS) && (lenRecv != 0))
103 {
104 if (osti_strncmp(buffer, "0x", 2) == 0)
105 {
106 max_dev = osti_strtoul (buffer, &pLastUsedChar, 0);
107 }
108 else
109 {
110 max_dev = osti_strtoul (buffer, &pLastUsedChar, 10);
111 }
112 }
113 SM_DBG3(("smGetRequirements: max_expander %d\n", max_dev));
114 /* memory requirement for Device Links, CACHE memory */
115 memoryRequirement->smMemory[SM_DEVICE_MEM_INDEX].singleElementLength = sizeof(smDeviceData_t);
116 memoryRequirement->smMemory[SM_DEVICE_MEM_INDEX].numElements = max_dev;
117 memoryRequirement->smMemory[SM_DEVICE_MEM_INDEX].totalLength =
118 (memoryRequirement->smMemory[SM_DEVICE_MEM_INDEX].singleElementLength) * (memoryRequirement->smMemory[SM_DEVICE_MEM_INDEX].numElements);
119 memoryRequirement->smMemory[SM_DEVICE_MEM_INDEX].alignment = 4;
120 memoryRequirement->smMemory[SM_DEVICE_MEM_INDEX].type = SM_CACHED_MEM;
121 memoryReqCount++;
122
123 /* memory requirement for IO inks, CACHE memory */
124 memoryRequirement->smMemory[SM_IO_MEM_INDEX].singleElementLength = sizeof(smIORequestBody_t);
125 memoryRequirement->smMemory[SM_IO_MEM_INDEX].numElements = SM_MAX_IO;
126 memoryRequirement->smMemory[SM_IO_MEM_INDEX].totalLength =
127 (memoryRequirement->smMemory[SM_IO_MEM_INDEX].singleElementLength) * (memoryRequirement->smMemory[SM_IO_MEM_INDEX].numElements);
128 memoryRequirement->smMemory[SM_IO_MEM_INDEX].alignment = 4;
129 memoryRequirement->smMemory[SM_IO_MEM_INDEX].type = SM_CACHED_MEM;
130 memoryReqCount++;
131
132 /* for debugging */
133 for (i=0;i< memoryReqCount;i++)
134 {
135 SM_DBG3(("smGetRequirements: index %d numElements %d totalLength %d singleElementLength %d alignment %d\n", i
136 , memoryRequirement->smMemory[i].numElements, memoryRequirement->smMemory[i].totalLength,
137 memoryRequirement->smMemory[i].singleElementLength,memoryRequirement->smMemory[i].alignment ));
138 }
139 /* set up memory requirement count */
140 memoryRequirement->count = memoryReqCount;
141
142 /* requirement for locks */
143 *maxNumLocks = SM_MAX_LOCKS;
144
145 /* setup the time tick */
146 *usecsPerTick = SM_USECS_PER_TICK;
147
148 /* set up the number of active IOs */
149 swConfig->maxActiveIOs = SM_MAX_IO;
150
151 /* set up the number of device handles */
152 swConfig->numDevHandles = SM_MAX_DEV;
153
154
155 return;
156 }
157
158 osGLOBAL bit32
smInitialize(smRoot_t * smRoot,agsaRoot_t * agRoot,smMemoryRequirement_t * memoryAllocated,smSwConfig_t * swConfig,bit32 usecsPerTick)159 smInitialize(
160 smRoot_t *smRoot,
161 agsaRoot_t *agRoot,
162 smMemoryRequirement_t *memoryAllocated,
163 smSwConfig_t *swConfig,
164 bit32 usecsPerTick
165 )
166 {
167 smIntRoot_t *smIntRoot;
168 smDeviceData_t *smDevice;
169 smIORequestBody_t *smIORequest;
170 smIntContext_t *smAllShared;
171 bit32 i;
172 bit32 max_dev = SM_MAX_DEV;
173 char *buffer;
174 bit32 buffLen;
175 bit32 lenRecv = 0;
176 static char tmpBuffer[DEFAULT_KEY_BUFFER_SIZE];
177 char *pLastUsedChar = agNULL;
178 char globalStr[] = "Global";
179 char iniParmsStr[] = "InitiatorParms";
180
181 SM_DBG2(("smInitialize: start\n"));
182
183 /* sanity check */
184 SM_ASSERT((agNULL != smRoot), "");
185 SM_ASSERT((agNULL != agRoot), "");
186 SM_ASSERT((agNULL != memoryAllocated), "");
187 SM_ASSERT((agNULL != swConfig), "");
188 SM_ASSERT((SM_ROOT_MEM_INDEX < memoryAllocated->count), "");
189 SM_ASSERT((SM_DEVICE_MEM_INDEX < memoryAllocated->count), "");
190 SM_ASSERT((SM_IO_MEM_INDEX < memoryAllocated->count), "");
191
192 /* Check the memory allocated */
193 for ( i = 0; i < memoryAllocated->count; i ++ )
194 {
195 /* If memory allocatation failed */
196 if (memoryAllocated->smMemory[i].singleElementLength &&
197 memoryAllocated->smMemory[i].numElements)
198 {
199 if ( (0 != memoryAllocated->smMemory[i].numElements)
200 && (0 == memoryAllocated->smMemory[i].totalLength) )
201 {
202 /* return failure */
203 SM_DBG1(("smInitialize: Memory[%d] singleElementLength = 0x%x numElements = 0x%x NOT allocated!!!\n",
204 i,
205 memoryAllocated->smMemory[i].singleElementLength,
206 memoryAllocated->smMemory[i].numElements));
207 return SM_RC_FAILURE;
208 }
209 }
210 }
211
212 /* for debugging */
213 for ( i = 0; i < memoryAllocated->count; i ++ )
214 {
215 SM_DBG3(("smInitialize: index %d virtPtr %p osHandle%p\n",i, memoryAllocated->smMemory[i].virtPtr, memoryAllocated->smMemory[i].osHandle));
216 SM_DBG3(("smInitialize: index %d phyAddrUpper 0x%x phyAddrLower 0x%x totalLength %d numElements %d\n", i,
217 memoryAllocated->smMemory[i].physAddrUpper,
218 memoryAllocated->smMemory[i].physAddrLower,
219 memoryAllocated->smMemory[i].totalLength,
220 memoryAllocated->smMemory[i].numElements));
221 SM_DBG3(("smInitialize: index %d singleElementLength 0x%x alignment 0x%x type %d reserved %d\n", i,
222 memoryAllocated->smMemory[i].singleElementLength,
223 memoryAllocated->smMemory[i].alignment,
224 memoryAllocated->smMemory[i].type,
225 memoryAllocated->smMemory[i].reserved));
226 }
227
228 /* SM's internal root */
229 smIntRoot = (smIntRoot_t *) (memoryAllocated->smMemory[SM_ROOT_MEM_INDEX].virtPtr);
230 smRoot->smData = (void *) smIntRoot;
231
232 smAllShared = (smIntContext_t *)&(smIntRoot->smAllShared);
233 /**< Initialize the TDM data part of the interrupt context */
234 smAllShared->smRootOsData.smRoot = smRoot;
235 smAllShared->smRootOsData.smAllShared = (void *) smAllShared;
236 gsmRoot = smRoot;
237 smAllShared->FCA = agTRUE;
238
239 /* Devices */
240 smDevice = (smDeviceData_t *) (memoryAllocated->smMemory[SM_DEVICE_MEM_INDEX].virtPtr);
241 smAllShared->DeviceMem = (smDeviceData_t *)smDevice;
242
243 /* IOs */
244 smIORequest = (smIORequestBody_t *) (memoryAllocated->smMemory[SM_IO_MEM_INDEX].virtPtr);
245 smAllShared->IOMem = (smIORequestBody_t *)smIORequest;
246
247 smAllShared->agRoot = agRoot;
248
249 smAllShared->usecsPerTick = usecsPerTick;
250
251 /**< initializes timers */
252 smInitTimers(smRoot);
253
254 /**< initializes devices */
255 buffer = tmpBuffer;
256 buffLen = sizeof(tmpBuffer);
257 sm_memset(buffer, 0, buffLen);
258 lenRecv = 0;
259 if ((tdsmGetTransportParam(
260 smRoot,
261 globalStr,
262 iniParmsStr,
263 agNULL,
264 agNULL,
265 agNULL,
266 agNULL,
267 "MaxTargets",
268 buffer,
269 buffLen,
270 &lenRecv
271 ) == SM_RC_SUCCESS) && (lenRecv != 0))
272 {
273 if (osti_strncmp(buffer, "0x", 2) == 0)
274 {
275 max_dev = osti_strtoul (buffer, &pLastUsedChar, 0);
276 }
277 else
278 {
279 max_dev = osti_strtoul (buffer, &pLastUsedChar, 10);
280 }
281 SM_DBG1(("smInitialize: MaxTargets %d\n", max_dev));
282 }
283
284 smDeviceDataInit(smRoot, max_dev);
285
286 /**< initializes IOs */
287 smIOInit(smRoot);
288
289 #ifdef SM_DEBUG
290 gSMDebugLevel = swConfig->SMDebugLevel;
291 #endif
292
293 return SM_RC_SUCCESS;
294 }
295
296 osGLOBAL void
smInitTimers(smRoot_t * smRoot)297 smInitTimers(
298 smRoot_t *smRoot
299 )
300 {
301 smIntRoot_t *smIntRoot = (smIntRoot_t *)smRoot->smData;
302 smIntContext_t *smAllShared = (smIntContext_t *)&smIntRoot->smAllShared;
303
304 SM_DBG2(("smInitTimers: start\n"));
305
306 /* initialize the timerlist */
307 SMLIST_INIT_HDR(&(smAllShared->timerlist));
308
309 return;
310 }
311
312 osGLOBAL void
smDeviceDataReInit(smRoot_t * smRoot,smDeviceData_t * oneDeviceData)313 smDeviceDataReInit(
314 smRoot_t *smRoot,
315 smDeviceData_t *oneDeviceData
316 )
317 {
318 int j=0;
319 smSatInternalIo_t *satIntIO;
320
321 SM_DBG2(("smDeviceDataReInit: start \n"));
322
323 if (oneDeviceData->satPendingIO != 0)
324 {
325 SM_DBG1(("smDeviceDataReInit: did %d\n", oneDeviceData->id));
326 SM_DBG1(("smDeviceDataReInit: satPendingIO %d satNCQMaxIO %d!!!\n", oneDeviceData->satPendingIO, oneDeviceData->satNCQMaxIO ));
327 SM_DBG1(("smDeviceDataReInit: satPendingNCQIO %d satPendingNONNCQIO %d!!!\n", oneDeviceData->satPendingNCQIO, oneDeviceData->satPendingNONNCQIO));
328 }
329
330 // oneDeviceData->smRoot = agNULL;
331 oneDeviceData->agDevHandle = agNULL;
332 oneDeviceData->valid = agFALSE;
333 oneDeviceData->SMAbortAll = agFALSE;
334 oneDeviceData->smDevHandle = agNULL;
335 oneDeviceData->directlyAttached = agFALSE;
336 oneDeviceData->agExpDevHandle = agNULL;
337 oneDeviceData->phyID = 0xFF;
338 oneDeviceData->SMNumOfFCA = 0;
339
340 /* default */
341 oneDeviceData->satDriveState = SAT_DEV_STATE_NORMAL;
342 oneDeviceData->satNCQMaxIO =SAT_NCQ_MAX;
343 oneDeviceData->satPendingIO = 0;
344 oneDeviceData->satPendingNCQIO = 0;
345 oneDeviceData->satPendingNONNCQIO = 0;
346 oneDeviceData->IDDeviceValid = agFALSE;
347 oneDeviceData->freeSATAFDMATagBitmap = 0;
348 oneDeviceData->NumOfFCA = 0;
349 oneDeviceData->NumOfIDRetries = 0;
350 oneDeviceData->ID_Retries = 0;
351 oneDeviceData->OSAbortAll = agFALSE;
352
353 sm_memset(oneDeviceData->satMaxLBA, 0, sizeof(oneDeviceData->satMaxLBA));
354 sm_memset(&(oneDeviceData->satIdentifyData), 0xFF, sizeof(agsaSATAIdentifyData_t));
355
356 oneDeviceData->satSaDeviceData = oneDeviceData;
357
358 satIntIO = (smSatInternalIo_t *)&(oneDeviceData->satIntIo[0]);
359 for (j = 0; j < SAT_MAX_INT_IO; j++)
360 {
361 SM_DBG2(("tdsaDeviceDataReInit: in loop of internal io free, id %d\n", satIntIO->id));
362 smsatFreeIntIoResource(smRoot, oneDeviceData, satIntIO);
363 satIntIO = satIntIO + 1;
364 }
365
366 return;
367 }
368 osGLOBAL void
smDeviceDataInit(smRoot_t * smRoot,bit32 max_dev)369 smDeviceDataInit(
370 smRoot_t *smRoot,
371 bit32 max_dev
372 )
373 {
374 smIntRoot_t *smIntRoot = (smIntRoot_t *)smRoot->smData;
375 smIntContext_t *smAllShared = (smIntContext_t *)&smIntRoot->smAllShared;
376 smDeviceData_t *smDeviceData = (smDeviceData_t *)smAllShared->DeviceMem;
377 int i,j;
378 smSatInternalIo_t *satIntIO;
379
380 SM_DBG2(("smDeviceDataInit: start \n"));
381
382 SMLIST_INIT_HDR(&(smAllShared->MainDeviceList));
383 SMLIST_INIT_HDR(&(smAllShared->FreeDeviceList));
384
385 for(i=0;i<(int)max_dev;i++)
386 {
387 SMLIST_INIT_ELEMENT(&(smDeviceData[i].FreeLink));
388 SMLIST_INIT_ELEMENT(&(smDeviceData[i].MainLink));
389 smDeviceData[i].id = i;
390 smDeviceData[i].smRoot = agNULL;
391 smDeviceData[i].agDevHandle = agNULL;
392 smDeviceData[i].valid = agFALSE;
393 smDeviceData[i].SMAbortAll = agFALSE;
394 smDeviceData[i].smDevHandle = agNULL;
395 smDeviceData[i].directlyAttached = agFALSE;
396 smDeviceData[i].agExpDevHandle = agNULL;
397 smDeviceData[i].phyID = 0xFF;
398 smDeviceData[i].SMNumOfFCA = 0;
399
400
401 SMLIST_INIT_HDR(&(smDeviceData[i].satIoLinkList));
402 SMLIST_INIT_HDR(&(smDeviceData[i].satFreeIntIoLinkList));
403 SMLIST_INIT_HDR(&(smDeviceData[i].satActiveIntIoLinkList));
404
405 /* default */
406 smDeviceData[i].satDriveState = SAT_DEV_STATE_NORMAL;
407 smDeviceData[i].satNCQMaxIO =SAT_NCQ_MAX;
408 smDeviceData[i].satPendingIO = 0;
409 smDeviceData[i].satPendingNCQIO = 0;
410 smDeviceData[i].satPendingNONNCQIO = 0;
411 smDeviceData[i].IDDeviceValid = agFALSE;
412 smDeviceData[i].freeSATAFDMATagBitmap = 0;
413 smDeviceData[i].NumOfFCA = 0;
414 smDeviceData[i].NumOfIDRetries = 0;
415 smDeviceData[i].ID_Retries = 0;
416 smDeviceData[i].OSAbortAll = agFALSE;
417 smInitTimerRequest(smRoot, &(smDeviceData[i].SATAIDDeviceTimer));
418
419 sm_memset(&(smDeviceData[i].satIdentifyData), 0xFF, sizeof(agsaSATAIdentifyData_t));
420 sm_memset(smDeviceData[i].satMaxLBA, 0, sizeof(smDeviceData[i].satMaxLBA));
421
422 smDeviceData[i].satSaDeviceData = &smDeviceData[i];
423
424 #if 1
425 satIntIO = &smDeviceData[i].satIntIo[0];
426 for (j = 0; j < SAT_MAX_INT_IO; j++)
427 {
428 SMLIST_INIT_ELEMENT (&satIntIO->satIntIoLink);
429 SMLIST_ENQUEUE_AT_TAIL (&satIntIO->satIntIoLink,
430 &smDeviceData[i].satFreeIntIoLinkList);
431 satIntIO->satOrgSmIORequest = agNULL;
432 satIntIO->id = j;
433 satIntIO = satIntIO + 1;
434 }
435 #endif
436
437 /* some other variables */
438 SMLIST_ENQUEUE_AT_TAIL(&(smDeviceData[i].FreeLink), &(smAllShared->FreeDeviceList));
439 }
440
441 return;
442 }
443
444 osGLOBAL void
smIOInit(smRoot_t * smRoot)445 smIOInit(
446 smRoot_t *smRoot
447 )
448 {
449 smIntRoot_t *smIntRoot = (smIntRoot_t *)smRoot->smData;
450 smIntContext_t *smAllShared = (smIntContext_t *)&smIntRoot->smAllShared;
451 smIORequestBody_t *smIOCommand = (smIORequestBody_t *)smAllShared->IOMem;
452 int i = 0;
453
454 SM_DBG3(("smIOInit: start\n"));
455
456 SMLIST_INIT_HDR(&(smAllShared->freeIOList));
457 SMLIST_INIT_HDR(&(smAllShared->mainIOList));
458
459 for(i=0;i<SM_MAX_IO;i++)
460 {
461 SMLIST_INIT_ELEMENT(&(smIOCommand[i].satIoBodyLink));
462 smIOCommand[i].id = i;
463 smIOCommand[i].InUse = agFALSE;
464 smIOCommand[i].ioStarted = agFALSE;
465 smIOCommand[i].ioCompleted = agFALSE;
466 smIOCommand[i].reTries = 0;
467
468 smIOCommand[i].smDevHandle = agNULL;
469 smIOCommand[i].smIORequest = agNULL;
470 smIOCommand[i].smIOToBeAbortedRequest = agNULL;
471 smIOCommand[i].transport.SATA.satIOContext.satOrgIOContext = agNULL;
472
473 sm_memset(&(smIOCommand[i].transport.SATA.agSATARequestBody), 0, sizeof(agsaSATAInitiatorRequest_t));
474
475
476 SMLIST_ENQUEUE_AT_TAIL(&(smIOCommand[i].satIoBodyLink), &(smAllShared->freeIOList));
477 }
478
479 return;
480 }
481
482 FORCEINLINE void
smIOReInit(smRoot_t * smRoot,smIORequestBody_t * smIORequestBody)483 smIOReInit(
484 smRoot_t *smRoot,
485 smIORequestBody_t *smIORequestBody
486 )
487 {
488 SM_DBG3(("smIOReInit: start\n"));
489 smIORequestBody->InUse = agTRUE;
490 smIORequestBody->ioStarted = agFALSE;
491 smIORequestBody->ioCompleted = agFALSE;
492 smIORequestBody->reTries = 0;
493 smIORequestBody->smDevHandle = agNULL;
494 smIORequestBody->smIORequest = agNULL;
495 smIORequestBody->smIOToBeAbortedRequest = agNULL;
496 smIORequestBody->transport.SATA.satIOContext.satOrgIOContext = agNULL;
497 /*sm_memset(&(smIORequestBody->transport.SATA.agSATARequestBody), 0, sizeof(agsaSATAInitiatorRequest_t));*/
498 return;
499 }
500
501 /* end smapi defined APIS */
502
503