initial implementation
[mirror/winof/.git] / core / al / al_dm.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id:$\r
31  */\r
32 \r
33 #include "al_ca.h"\r
34 #include "al_debug.h"\r
35 #include "al_dm.h"\r
36 #include "al_mgr.h"\r
37 #include "ib_common.h"\r
38 \r
39 \r
40 /*\r
41  * This code implements a minimal device management agent.\r
42  */\r
43 \r
44 \r
45 static dm_agent_t*                              gp_dm_agent = NULL;\r
46 \r
47 \r
48 #define SVC_REG_TIMEOUT                         2000            // Milliseconds\r
49 #define SVC_REG_RETRY_CNT                       3\r
50 #define DM_CLASS_RESP_TIME_VALUE        20\r
51 \r
52 \r
53 #define SET_NIBBLE( nibble_array, nibble_num, value )                                           \\r
54 {                                                                                                                                                       \\r
55         ((uint8_t*)(nibble_array))[(nibble_num) >> 1]   = (uint8_t)                             \\r
56                 ((((nibble_num) & 1) == 0) ?                                                                            \\r
57                         ((uint8_t*)(nibble_array))[(nibble_num) >> 1] & 0x0f :                  \\r
58                         ((uint8_t*)(nibble_array))[(nibble_num) >> 1] & 0xf0);                  \\r
59         ((uint8_t*)(nibble_array))[(nibble_num) >> 1] |=                                                \\r
60                 ( ((nibble_num) & 1) == 0) ? ((value) << 4) : ((value) & 0x0f);         \\r
61 }\r
62 \r
63 \r
64 void\r
65 free_ioc(\r
66         IN                              al_obj_t*                                       p_obj );\r
67 \r
68 void\r
69 free_svc_entry(\r
70         IN                              al_obj_t*                                       p_obj );\r
71 \r
72 al_iou_t*\r
73 acquire_iou(\r
74         IN              const   ib_net64_t                                      ca_guid );\r
75 \r
76 al_iou_t*\r
77 get_iou(\r
78         IN              const   ib_ioc_handle_t                         h_ioc );\r
79 \r
80 ib_ioc_handle_t\r
81 get_ioc(\r
82         IN              const   ib_ca_handle_t                          h_ca );\r
83 \r
84 ib_api_status_t\r
85 add_ioc(\r
86         IN                              al_iou_t*                                       p_iou,\r
87         IN                              ib_ioc_handle_t                         h_ioc );\r
88 \r
89 void\r
90 ioc_change(\r
91         IN                              ib_ioc_handle_t                         h_ioc );\r
92 \r
93 void\r
94 iou_change(\r
95         IN                              al_iou_t*                                       p_iou );\r
96 \r
97 ib_api_status_t\r
98 set_port_dm_attr(\r
99         IN                              al_iou_port_t*                          p_iou_port );\r
100 \r
101 void\r
102 iou_port_svc_reg_cb(\r
103         IN                              ib_reg_svc_rec_t*                       p_reg_svc_rec );\r
104 \r
105 void\r
106 destroying_dm_agent(\r
107         IN                              al_obj_t*                                       p_obj );\r
108 \r
109 void\r
110 free_dm_agent(\r
111         IN                              al_obj_t*                                       p_obj );\r
112 \r
113 ib_api_status_t\r
114 dm_agent_reg_pnp(\r
115         IN                              ib_pnp_class_t                          pnp_class,\r
116         IN                              ib_pnp_handle_t*                        ph_pnp );\r
117 \r
118 ib_api_status_t\r
119 dm_agent_pnp_cb(\r
120         IN                              ib_pnp_rec_t*                           p_pnp_rec );\r
121 \r
122 ib_api_status_t\r
123 create_iou(\r
124         IN                              ib_pnp_rec_t*                           p_pnp_rec );\r
125 \r
126 void\r
127 cleanup_iou(\r
128         IN                              al_obj_t*                                       p_obj );\r
129 \r
130 void\r
131 free_iou(\r
132         IN                              al_obj_t*                                       p_obj );\r
133 \r
134 ib_api_status_t\r
135 create_iou_port(\r
136         IN                              ib_pnp_port_rec_t*                      p_pnp_rec );\r
137 \r
138 void\r
139 destroying_iou_port(\r
140         IN                              al_obj_t*                                       p_obj );\r
141 \r
142 void\r
143 free_iou_port(\r
144         IN                              al_obj_t*                                       p_obj );\r
145 \r
146 void\r
147 iou_port_event_cb(\r
148         IN                              ib_async_event_rec_t            *p_event_rec );\r
149 \r
150 void\r
151 dm_agent_send_cb(\r
152         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
153         IN                              void*                                           mad_svc_context,\r
154         IN                              ib_mad_element_t*                       p_mad_response );\r
155 \r
156 void\r
157 dm_agent_recv_cb(\r
158         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
159         IN                              void*                                           mad_svc_context,\r
160         IN                              ib_mad_element_t*                       p_mad_request );\r
161 \r
162 void\r
163 dm_agent_get(\r
164         IN                              al_iou_port_t*                          p_iou_port,\r
165         IN                              ib_mad_t*                                       p_mad_req,\r
166         IN                              ib_mad_t*                                       p_mad_rsp );\r
167 \r
168 void\r
169 dm_agent_set(\r
170         IN                              al_iou_port_t*                          p_iou_port,\r
171         IN                              ib_mad_t*                                       p_mad_req,\r
172         IN                              ib_mad_t*                                       p_mad_rsp );\r
173 \r
174 void\r
175 get_class_port_info(\r
176         IN                              al_iou_t*                                       p_iou,\r
177         IN                              ib_dm_mad_t*                            p_dm_mad );\r
178 \r
179 void\r
180 get_io_unit_info(\r
181         IN                              al_iou_t*                                       p_iou,\r
182         IN                              ib_dm_mad_t*                            p_dm_mad );\r
183 \r
184 void\r
185 get_ioc_profile(\r
186         IN                              al_iou_t*                                       p_iou,\r
187         IN                              uint8_t                                         slot,\r
188         IN                              ib_dm_mad_t*                            p_dm_mad );\r
189 \r
190 void\r
191 get_svc_entries(\r
192         IN                              al_iou_t*                                       p_iou,\r
193         IN                              uint8_t                                         slot,\r
194         IN                              uint8_t                                         svc_num_lo,\r
195         IN                              uint8_t                                         svc_num_hi,\r
196         IN                              ib_dm_mad_t*                            p_dm_mad );\r
197 \r
198 \r
199 \r
200 \r
201 ib_api_status_t\r
202 ib_create_ioc(\r
203         IN              const   ib_ca_handle_t                          h_ca,\r
204         IN              const   ib_ioc_profile_t* const         p_ioc_profile,\r
205                 OUT                     ib_ioc_handle_t* const          ph_ioc )\r
206 {\r
207         ib_ioc_handle_t                 h_ioc;\r
208 \r
209         CL_ENTER( AL_DBG_IOC, g_al_dbg_lvl );\r
210 \r
211         if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) )\r
212         {\r
213                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_CA_HANDLE\n") );\r
214                 return IB_INVALID_CA_HANDLE;\r
215         }\r
216         if( !p_ioc_profile || ph_ioc )\r
217         {\r
218                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
219                 return IB_INVALID_PARAMETER;\r
220         }\r
221 \r
222         /* Get an IOC. */\r
223         h_ioc = get_ioc( h_ca );\r
224         if( !h_ioc )\r
225                 return IB_INSUFFICIENT_MEMORY;\r
226 \r
227         /* Save the IOC profile. */\r
228         cl_memcpy( &h_ioc->ioc_profile, p_ioc_profile, sizeof(ib_ioc_profile_t) );\r
229 \r
230         /* Clear the service entry count. */\r
231         h_ioc->ioc_profile.num_svc_entries = 0;\r
232 \r
233         /* Return the IOC handle to the user. */\r
234         *ph_ioc = h_ioc;\r
235 \r
236         CL_EXIT( AL_DBG_IOC, g_al_dbg_lvl );\r
237         return IB_SUCCESS;\r
238 }\r
239 \r
240 \r
241 \r
242 ib_api_status_t\r
243 ib_destroy_ioc(\r
244         IN              const   ib_ioc_handle_t                         h_ioc )\r
245 {\r
246         CL_ENTER( AL_DBG_IOC, g_al_dbg_lvl );\r
247 \r
248         if( AL_OBJ_INVALID_HANDLE( h_ioc, AL_OBJ_TYPE_H_IOC ) )\r
249         {\r
250                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_HANDLE\n") );\r
251                 return IB_INVALID_HANDLE;\r
252         }\r
253 \r
254         ref_al_obj( &h_ioc->obj );\r
255         h_ioc->obj.pfn_destroy( &h_ioc->obj, NULL );\r
256 \r
257         CL_EXIT( AL_DBG_IOC, g_al_dbg_lvl );\r
258         return IB_SUCCESS;\r
259 }\r
260 \r
261 \r
262 \r
263 /*\r
264  * Free an IOC.\r
265  */\r
266 void\r
267 free_ioc(\r
268         IN                              al_obj_t*                                       p_obj )\r
269 {\r
270         ib_ioc_handle_t                 h_ioc;\r
271 \r
272         CL_ASSERT( p_obj );\r
273 \r
274         h_ioc = PARENT_STRUCT( p_obj, al_ioc_t, obj );\r
275 \r
276         /*\r
277          * To maintain slot ordering, IOCs attached to an IO unit are freed when\r
278          * the IO unit is destroyed.  Otherwise, unattached IOCs may be freed now.\r
279          */\r
280         if( h_ioc->p_iou )\r
281         {\r
282                 /* Mark the IOC slot as empty. */\r
283                 h_ioc->state = EMPTY_SLOT;\r
284                 reset_al_obj( p_obj );\r
285                 deref_al_obj( &h_ioc->p_iou->obj );\r
286 \r
287                 /* Report that a change occurred on the IOC. */\r
288                 ioc_change( h_ioc );\r
289         }\r
290         else\r
291         {\r
292                 /* Unattached IOCs can be destroyed. */\r
293                 destroy_al_obj( p_obj );\r
294                 cl_free( h_ioc );\r
295         }\r
296 }\r
297 \r
298 \r
299 \r
300 ib_api_status_t\r
301 ib_reg_ioc(\r
302         IN              const   ib_ioc_handle_t                         h_ioc )\r
303 {\r
304         al_iou_t*                               p_iou;\r
305         ib_api_status_t                 status;\r
306 \r
307         CL_ENTER( AL_DBG_IOC, g_al_dbg_lvl );\r
308 \r
309         if( AL_OBJ_INVALID_HANDLE( h_ioc, AL_OBJ_TYPE_H_IOC ) )\r
310         {\r
311                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_HANDLE\n") );\r
312                 return IB_INVALID_HANDLE;\r
313         }\r
314 \r
315         /* Get an IO unit for this IOC. */\r
316         p_iou = get_iou( h_ioc );\r
317         if( !p_iou )\r
318                 return IB_INSUFFICIENT_MEMORY;\r
319 \r
320         /* Register the IOC with the IO unit. */\r
321         status = add_ioc( p_iou, h_ioc );\r
322 \r
323         CL_EXIT( AL_DBG_IOC, g_al_dbg_lvl );\r
324         return status;\r
325 }\r
326 \r
327 \r
328 \r
329 ib_api_status_t\r
330 ib_add_svc_entry(\r
331         IN              const   ib_ioc_handle_t                         h_ioc,\r
332         IN              const   ib_svc_entry_t* const           p_svc_entry,\r
333                 OUT                     ib_svc_handle_t* const          ph_svc )\r
334 {\r
335         ib_svc_handle_t                 h_svc;\r
336         ib_api_status_t                 status;\r
337 \r
338         CL_ENTER( AL_DBG_IOC, g_al_dbg_lvl );\r
339 \r
340         if( AL_OBJ_INVALID_HANDLE( h_ioc, AL_OBJ_TYPE_H_IOC ) )\r
341         {\r
342                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_HANDLE\n") );\r
343                 return IB_INVALID_HANDLE;\r
344         }\r
345         if( !p_svc_entry || !ph_svc )\r
346         {\r
347                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
348                 return IB_INVALID_PARAMETER;\r
349         }\r
350 \r
351         /*\r
352          * Synchronize the addition of a service entry with the removal.\r
353          * Cannot hold a lock on the IOC when attaching a service entry\r
354          * object.  Wait here until the IOC is no longer in use.\r
355          */\r
356         cl_spinlock_acquire( &h_ioc->obj.lock );\r
357         while( h_ioc->in_use_cnt )\r
358         {\r
359                 cl_spinlock_release( &h_ioc->obj.lock );\r
360                 cl_thread_suspend( 0 );\r
361                 cl_spinlock_acquire( &h_ioc->obj.lock );\r
362         }\r
363         /* Flag the IOC as in use by this thread. */\r
364         cl_atomic_inc( &h_ioc->in_use_cnt );\r
365         cl_spinlock_release( &h_ioc->obj.lock );\r
366 \r
367         /* Check the current service entry count. */\r
368         if( h_ioc->ioc_profile.num_svc_entries == MAX_NUM_SVC_ENTRIES )\r
369         {\r
370                 cl_spinlock_release( &h_ioc->obj.lock );\r
371                 CL_EXIT( AL_DBG_IOC, g_al_dbg_lvl );\r
372                 return IB_INSUFFICIENT_RESOURCES;\r
373         }\r
374         h_svc = cl_zalloc( sizeof( ib_svc_handle_t ) );\r
375         if( !h_svc )\r
376         {\r
377                 CL_EXIT( AL_DBG_IOC, g_al_dbg_lvl );\r
378                 return IB_INSUFFICIENT_MEMORY;\r
379         }\r
380 \r
381         /* Construct the service entry. */\r
382         construct_al_obj( &h_svc->obj, AL_OBJ_TYPE_H_SVC_ENTRY );\r
383 \r
384         /* Save the service entry. */\r
385         cl_memcpy( &h_svc->svc_entry, p_svc_entry, sizeof( ib_svc_entry_t ) );\r
386 \r
387         /* Initialize the service entry object. */\r
388         status = init_al_obj( &h_svc->obj, h_svc, FALSE, NULL, NULL,\r
389                 free_svc_entry );\r
390         if( status != IB_SUCCESS )\r
391         {\r
392                 free_svc_entry( &h_svc->obj );\r
393                 CL_EXIT( AL_DBG_IOC, g_al_dbg_lvl );\r
394                 return status;\r
395         }\r
396 \r
397         /* Attach the service entry to the IOC. */\r
398         status = attach_al_obj( &h_ioc->obj, &h_svc->obj );\r
399         if( status != IB_SUCCESS )\r
400         {\r
401                 h_svc->obj.pfn_destroy( &h_svc->obj, NULL );\r
402                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
403                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
404                 return status;\r
405         }\r
406 \r
407         h_ioc->ioc_profile.num_svc_entries++;\r
408 \r
409         /* Indicate that a change occured on the IOC. */\r
410         ioc_change( h_ioc );\r
411 \r
412         /* No longer in use by this thread. */\r
413         cl_atomic_dec( &h_ioc->in_use_cnt );\r
414 \r
415         /* Return the service entry handle to the user. */\r
416         *ph_svc = h_svc;\r
417 \r
418         /* Release the reference taken in init_al_obj. */\r
419         deref_al_obj( &h_svc->obj );\r
420 \r
421         CL_EXIT( AL_DBG_IOC, g_al_dbg_lvl );\r
422         return IB_SUCCESS;\r
423 }\r
424 \r
425 \r
426 \r
427 ib_api_status_t\r
428 ib_remove_svc_entry(\r
429         IN              const   ib_svc_handle_t                         h_svc )\r
430 {\r
431         ib_ioc_handle_t                 h_ioc;\r
432 \r
433         CL_ENTER( AL_DBG_IOC, g_al_dbg_lvl );\r
434 \r
435         if( AL_OBJ_INVALID_HANDLE( h_svc, AL_OBJ_TYPE_H_SVC_ENTRY ) )\r
436         {\r
437                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_HANDLE\n") );\r
438                 return IB_INVALID_HANDLE;\r
439         }\r
440 \r
441         h_ioc = PARENT_STRUCT( h_svc->obj.p_parent_obj, al_ioc_t, obj );\r
442 \r
443         /*\r
444          * Synchronize the removal of a service entry with the addition.\r
445          * Cannot hold a lock on the IOC when detaching a service entry\r
446          * object.  Wait here until the IOC is no longer in use.\r
447          */\r
448         cl_spinlock_acquire( &h_ioc->obj.lock );\r
449         while( h_ioc->in_use_cnt )\r
450         {\r
451                 cl_spinlock_release( &h_ioc->obj.lock );\r
452                 cl_thread_suspend( 0 );\r
453                 cl_spinlock_acquire( &h_ioc->obj.lock );\r
454         }\r
455         /* Flag the IOC as in use by this thread. */\r
456         cl_atomic_inc( &h_ioc->in_use_cnt );\r
457         cl_spinlock_release( &h_ioc->obj.lock );\r
458 \r
459         /*\r
460          * Synchronously destroy the service entry.\r
461          * The service handle is invalid when this call returns.\r
462          */\r
463         ref_al_obj( &h_svc->obj );\r
464         h_svc->obj.pfn_destroy( &h_svc->obj, NULL );\r
465 \r
466         /* Decrement the service entry count. */\r
467         h_ioc->ioc_profile.num_svc_entries--;\r
468 \r
469         /* Indicate that a change occured on the IOC. */\r
470         ioc_change( h_ioc );\r
471 \r
472         /* No longer in use by this thread. */\r
473         cl_atomic_dec( &h_ioc->in_use_cnt );\r
474 \r
475         CL_EXIT( AL_DBG_IOC, g_al_dbg_lvl );\r
476         return IB_SUCCESS;\r
477 }\r
478 \r
479 \r
480 \r
481 /*\r
482  * Free a service entry.\r
483  */\r
484 void\r
485 free_svc_entry(\r
486         IN                              al_obj_t*                                       p_obj )\r
487 {\r
488         ib_svc_handle_t                 h_svc;\r
489 \r
490         CL_ASSERT( p_obj );\r
491         h_svc = PARENT_STRUCT( p_obj, al_svc_entry_t, obj );\r
492 \r
493         destroy_al_obj( &h_svc->obj );\r
494         cl_free( h_svc );\r
495 }\r
496 \r
497 \r
498 \r
499 /*\r
500  * Acquire the IO unit matching the given CA GUID.\r
501  */\r
502 al_iou_t*\r
503 acquire_iou(\r
504         IN              const   ib_net64_t                                      ca_guid )\r
505 {\r
506         cl_list_item_t*                 p_iou_item;\r
507         al_obj_t*                               p_obj;\r
508         al_iou_t*                               p_iou;\r
509 \r
510         /* Search for an existing IO unit matching the CA GUID. */\r
511         cl_spinlock_acquire( &gp_dm_agent->obj.lock );\r
512         for( p_iou_item = cl_qlist_head( &gp_dm_agent->obj.obj_list );\r
513                 p_iou_item != cl_qlist_end( &gp_dm_agent->obj.obj_list );\r
514                 p_iou_item = cl_qlist_next( p_iou_item ) )\r
515         {\r
516                 p_obj = PARENT_STRUCT( p_iou_item, al_obj_t, pool_item );\r
517                 p_iou = PARENT_STRUCT( p_obj, al_iou_t, obj );\r
518 \r
519                 /* Check for a GUID match. */\r
520                 if( p_iou->obj.p_ci_ca->verbs.guid == ca_guid )\r
521                 {\r
522                         /* Reference the IO unit on behalf of the client. */\r
523                         ref_al_obj( &p_iou->obj );\r
524 \r
525                         cl_spinlock_release( &gp_dm_agent->obj.lock );\r
526                         return p_iou;\r
527                 }\r
528         }\r
529         cl_spinlock_release( &gp_dm_agent->obj.lock );\r
530 \r
531         return NULL;\r
532 }\r
533 \r
534 \r
535 \r
536 /*\r
537  * Get the IO unit for the given IOC.\r
538  */\r
539 al_iou_t*\r
540 get_iou(\r
541         IN              const   ib_ioc_handle_t                         h_ioc )\r
542 {\r
543         CL_ASSERT( h_ioc );\r
544 \r
545         /* Check if the IOC is already attached to an IO unit. */\r
546         if( h_ioc->p_iou )\r
547                 return h_ioc->p_iou;\r
548 \r
549         /* The IOC is a new slot.  Acquire the IO unit. */\r
550         return acquire_iou( h_ioc->obj.p_ci_ca->verbs.guid );\r
551 }\r
552 \r
553 \r
554 \r
555 ib_ioc_handle_t\r
556 get_ioc(\r
557         IN              const   ib_ca_handle_t                          h_ca )\r
558 {\r
559         cl_list_item_t*                 p_ioc_item;\r
560         al_iou_t*                               p_iou;\r
561         ib_ioc_handle_t                 h_ioc;\r
562         boolean_t                               found;\r
563         ib_api_status_t                 status;\r
564 \r
565         found = FALSE;\r
566         h_ioc = NULL;\r
567 \r
568         /* Acquire the IO unit. */\r
569         p_iou = acquire_iou( h_ca->obj.p_ci_ca->verbs.guid );\r
570 \r
571         if( p_iou )\r
572         {\r
573                 /* Search for an empty IOC slot in the IO unit. */\r
574                 cl_spinlock_acquire( &p_iou->obj.lock );\r
575                 for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list );\r
576                         (p_ioc_item != cl_qlist_end( &p_iou->ioc_list )) && !found;\r
577                         p_ioc_item = cl_qlist_next( p_ioc_item ) )\r
578                 {\r
579                         h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item );\r
580 \r
581                         if( h_ioc->state == EMPTY_SLOT )\r
582                         {\r
583                                 /*\r
584                                  * An empty slot was found.\r
585                                  * Change the state to indicate that the slot is in use.\r
586                                  */\r
587                                 h_ioc->state = SLOT_IN_USE;\r
588                                 found = TRUE;\r
589                         }\r
590                 }\r
591                 cl_spinlock_release( &p_iou->obj.lock );\r
592         }\r
593 \r
594         /* Allocate a new IOC if one was not found. */\r
595         if( !found )\r
596         {\r
597                 h_ioc = cl_zalloc( sizeof( al_ioc_t ) );\r
598                 if( !h_ioc )\r
599                         return NULL;\r
600 \r
601                 /* Construct the IOC. */\r
602                 construct_al_obj( &h_ioc->obj, AL_OBJ_TYPE_H_IOC );\r
603 \r
604                 /* Initialize the IOC object. */\r
605                 status =\r
606                         init_al_obj( &h_ioc->obj, h_ioc, FALSE, NULL, NULL, free_ioc );\r
607                 if( status != IB_SUCCESS )\r
608                 {\r
609                         free_ioc( &h_ioc->obj );\r
610                         return NULL;\r
611                 }\r
612         }\r
613 \r
614         /* Attach the IOC to the CA. */\r
615         status = attach_al_obj( &h_ca->obj, &h_ioc->obj );\r
616         if( status != IB_SUCCESS )\r
617         {\r
618                 h_ioc->obj.pfn_destroy( &h_ioc->obj, NULL );\r
619                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
620                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
621                 return NULL;\r
622         }\r
623 \r
624         /* Release the reference taken in init_al_obj. */\r
625         deref_al_obj( &h_ioc->obj );\r
626 \r
627         return h_ioc;\r
628 }\r
629 \r
630 \r
631 \r
632 ib_api_status_t\r
633 add_ioc(\r
634         IN                              al_iou_t*                                       p_iou,\r
635         IN                              ib_ioc_handle_t                         h_ioc )\r
636 {\r
637         cl_list_item_t*                 p_list_item;\r
638         al_obj_t*                               p_obj;\r
639         al_iou_port_t*                  p_iou_port;\r
640         ib_api_status_t                 status;\r
641 \r
642         CL_ASSERT( p_iou );\r
643         CL_ASSERT( h_ioc );\r
644 \r
645         /* Attach the IOC to the IO unit. */\r
646         if( !h_ioc->p_iou )\r
647         {\r
648                 cl_spinlock_acquire( &p_iou->obj.lock );\r
649 \r
650                 /* Make sure the IO unit can support the new IOC slot. */\r
651                 if( cl_qlist_count( &p_iou->ioc_list ) >=\r
652                         ( sizeof( ((ib_iou_info_t*)0)->controller_list ) - 1) )\r
653                 {\r
654                         cl_spinlock_release( &p_iou->obj.lock );\r
655                         deref_al_obj( &p_iou->obj );\r
656                         return IB_INSUFFICIENT_RESOURCES;\r
657                 }\r
658 \r
659                 /* Add a new IOC slot to the IO unit. */\r
660                 cl_qlist_insert_tail( &p_iou->ioc_list, &h_ioc->iou_item );\r
661                 h_ioc->p_iou = p_iou;\r
662 \r
663                 cl_spinlock_release( &p_iou->obj.lock );\r
664         }\r
665         else\r
666         {\r
667                 /* The IOC is being added to an empty IO unit slot. */\r
668                 CL_ASSERT( h_ioc->p_iou == p_iou );\r
669                 CL_ASSERT( h_ioc->state == SLOT_IN_USE );\r
670         }\r
671 \r
672         /* Enable the IOC. */\r
673         h_ioc->state = IOC_ACTIVE;\r
674 \r
675         /* Indicate that a change occured on the IO unit. */\r
676         iou_change( p_iou );\r
677 \r
678         /* Flag each port on the IO unit CA as supporting device management. */\r
679         status = IB_SUCCESS;\r
680         cl_spinlock_acquire( &p_iou->obj.lock );\r
681         for( p_list_item = cl_qlist_head( &p_iou->obj.obj_list );\r
682                  p_list_item != cl_qlist_end( &p_iou->obj.obj_list );\r
683                  p_list_item = cl_qlist_next( p_list_item ) )\r
684         {\r
685                 p_obj = PARENT_STRUCT( p_list_item, al_obj_t, pool_item );\r
686                 p_iou_port = PARENT_STRUCT( p_obj, al_iou_port_t, obj );\r
687 \r
688                 status = set_port_dm_attr( p_iou_port );\r
689                 if( status != IB_SUCCESS ) break;\r
690         }\r
691         cl_spinlock_release( &p_iou->obj.lock );\r
692 \r
693         if( status != IB_SUCCESS )\r
694                 h_ioc->state = SLOT_IN_USE;\r
695 \r
696         return status;\r
697 }\r
698 \r
699 \r
700 \r
701 void\r
702 ioc_change(\r
703         IN                              ib_ioc_handle_t                         h_ioc )\r
704 {\r
705         CL_ASSERT( h_ioc );\r
706 \r
707         /* Report a change to the IO unit which the IOC is attached. */\r
708         if( h_ioc->p_iou ) iou_change( h_ioc->p_iou );\r
709 }\r
710 \r
711 \r
712 \r
713 void\r
714 iou_change(\r
715         IN                              al_iou_t*                                       p_iou )\r
716 {\r
717         CL_ASSERT( p_iou );\r
718 \r
719         /* Increment the IO unit change counter. */\r
720         cl_spinlock_acquire( &p_iou->obj.lock );\r
721         p_iou->change_id++;\r
722         cl_spinlock_release( &p_iou->obj.lock );\r
723 }\r
724 \r
725 \r
726 \r
727 ib_api_status_t\r
728 set_port_dm_attr(\r
729         IN                              al_iou_port_t*                          p_iou_port )\r
730 {\r
731         ib_port_attr_mod_t              port_attr_mod;\r
732         ib_reg_svc_req_t                reg_svc_req;\r
733         ib_api_status_t                 status;\r
734 \r
735         CL_ASSERT( p_iou_port );\r
736 \r
737         /* Initialize a port attribute modification structure. */\r
738         cl_memclr( &port_attr_mod, sizeof( ib_port_attr_mod_t ) );\r
739         port_attr_mod.cap.dev_mgmt = TRUE;\r
740 \r
741         /* Flag each port on the IO unit CA as supporting device management. */\r
742         status = ib_modify_ca( p_iou_port->obj.p_ci_ca->h_ca, p_iou_port->port_num,\r
743                 IB_CA_MOD_IS_DEV_MGMT_SUPPORTED, &port_attr_mod );\r
744 \r
745         if( status != IB_SUCCESS )\r
746                 return status;\r
747 \r
748         /* The register a service with the SA if one is needed. */\r
749         if( !p_iou_port->svc_handle )\r
750         {\r
751                 /* Build the service registration request. */\r
752                 cl_memclr( &reg_svc_req, sizeof( ib_reg_svc_req_t ) );\r
753 \r
754                 reg_svc_req.svc_rec.service_lease = 0xffffffff;\r
755                 strncpy( (char*)reg_svc_req.svc_rec.service_name, DM_SVC_NAME,\r
756                         sizeof( reg_svc_req.svc_rec.service_name ) );\r
757                 reg_svc_req.svc_rec.service_gid = p_iou_port->port_gid;\r
758                 reg_svc_req.port_guid = p_iou_port->port_guid;\r
759 \r
760                 reg_svc_req.timeout_ms          = SVC_REG_TIMEOUT;\r
761                 reg_svc_req.retry_cnt           = SVC_REG_RETRY_CNT;\r
762                 reg_svc_req.svc_context         = p_iou_port;\r
763                 reg_svc_req.pfn_reg_svc_cb      = iou_port_svc_reg_cb;\r
764                 reg_svc_req.svc_data_mask       = IB_SR_COMPMASK_SGID |\r
765                                                                           IB_SR_COMPMASK_SPKEY |\r
766                                                                           IB_SR_COMPMASK_SLEASE |\r
767                                                                           IB_SR_COMPMASK_SNAME;\r
768 \r
769                 /* Reference the IO unit port on behalf of the ib_reg_svc call. */\r
770                 ref_al_obj( &p_iou_port->obj );\r
771 \r
772                 status = ib_reg_svc( gh_al, &reg_svc_req, &p_iou_port->svc_handle );\r
773 \r
774                 if( status != IB_SUCCESS )\r
775                 {\r
776                         deref_al_obj( &p_iou_port->obj );\r
777 \r
778                         /* Ignore this error - the SM will sweep port attribute changes. */\r
779                         status = IB_SUCCESS;\r
780                 }\r
781         }\r
782 \r
783         return status;\r
784 }\r
785 \r
786 \r
787 \r
788 void\r
789 iou_port_svc_reg_cb(\r
790         IN                              ib_reg_svc_rec_t*                       p_reg_svc_rec )\r
791 {\r
792         al_iou_port_t*                  p_iou_port;\r
793 \r
794         CL_ASSERT( p_reg_svc_rec );\r
795 \r
796         p_iou_port = (al_iou_port_t* __ptr64)p_reg_svc_rec->svc_context;\r
797 \r
798         if( p_reg_svc_rec->req_status != IB_SUCCESS )\r
799                 deref_al_obj( &p_iou_port->obj );\r
800 }\r
801 \r
802 \r
803 /*\r
804  * Device Management Agent\r
805  */\r
806 \r
807 \r
808 /*\r
809  * Create the device management agent.\r
810  */\r
811 ib_api_status_t\r
812 create_dm_agent(\r
813         IN                              al_obj_t*       const                   p_parent_obj )\r
814 {\r
815         cl_status_t                             cl_status;\r
816         ib_api_status_t                 status;\r
817 \r
818         CL_ASSERT( p_parent_obj );\r
819         CL_ASSERT( !gp_dm_agent );\r
820 \r
821         gp_dm_agent = cl_zalloc( sizeof( dm_agent_t ) );\r
822         if( !gp_dm_agent )\r
823                 return IB_INSUFFICIENT_MEMORY;\r
824 \r
825         /* Construct the device management agent. */\r
826         construct_al_obj( &gp_dm_agent->obj, AL_OBJ_TYPE_DM );\r
827         cl_spinlock_construct( &gp_dm_agent->lock );\r
828 \r
829         cl_status = cl_spinlock_init( &gp_dm_agent->lock );\r
830         if( cl_status != CL_SUCCESS )\r
831         {\r
832                 free_dm_agent( &gp_dm_agent->obj );\r
833                 return ib_convert_cl_status( cl_status );\r
834         }\r
835 \r
836         /* Initialize the device management agent object. */\r
837         status = init_al_obj( &gp_dm_agent->obj, gp_dm_agent, TRUE,\r
838                 destroying_dm_agent, NULL, free_dm_agent );\r
839         if( status != IB_SUCCESS )\r
840         {\r
841                 free_dm_agent( &gp_dm_agent->obj );\r
842                 return status;\r
843         }\r
844 \r
845         /* Attach the device management agent to the parent object. */\r
846         status = attach_al_obj( p_parent_obj, &gp_dm_agent->obj );\r
847         if( status != IB_SUCCESS )\r
848         {\r
849                 gp_dm_agent->obj.pfn_destroy( &gp_dm_agent->obj, NULL );\r
850                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
851                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
852                 return status;\r
853         }\r
854 \r
855         /* Register for CA PnP events. */\r
856         status = dm_agent_reg_pnp( IB_PNP_CA, &gp_dm_agent->h_ca_pnp );\r
857         if (status != IB_SUCCESS)\r
858         {\r
859                 gp_dm_agent->obj.pfn_destroy( &gp_dm_agent->obj, NULL );\r
860                 return status;\r
861         }\r
862 \r
863         /* Register for port PnP events. */\r
864         status = dm_agent_reg_pnp( IB_PNP_PORT, &gp_dm_agent->h_port_pnp );\r
865         if (status != IB_SUCCESS)\r
866         {\r
867                 gp_dm_agent->obj.pfn_destroy( &gp_dm_agent->obj, NULL );\r
868                 return status;\r
869         }\r
870 \r
871         /* Release the reference taken in init_al_obj. */\r
872         deref_al_obj( &gp_dm_agent->obj );\r
873 \r
874         return IB_SUCCESS;\r
875 }\r
876 \r
877 \r
878 \r
879 /*\r
880  * Pre-destroy the device management agent.\r
881  */\r
882 void\r
883 destroying_dm_agent(\r
884         IN                              al_obj_t*                                       p_obj )\r
885 {\r
886         ib_api_status_t                 status;\r
887 \r
888         CL_ASSERT( p_obj );\r
889         CL_ASSERT( gp_dm_agent == PARENT_STRUCT( p_obj, dm_agent_t, obj ) );\r
890         UNUSED_PARAM( p_obj );\r
891 \r
892         /* Mark that we're destroying the agent. */\r
893         cl_spinlock_acquire( &gp_dm_agent->lock );\r
894         gp_dm_agent->destroying = TRUE;\r
895         cl_spinlock_release( &gp_dm_agent->lock );\r
896 \r
897         /* Deregister for port PnP events. */\r
898         if( gp_dm_agent->h_port_pnp )\r
899         {\r
900                 status = ib_dereg_pnp( gp_dm_agent->h_port_pnp,\r
901                         (ib_pfn_destroy_cb_t)deref_al_obj );\r
902                 CL_ASSERT( status == IB_SUCCESS );\r
903         }\r
904 \r
905         /* Deregister for CA PnP events. */\r
906         if( gp_dm_agent->h_ca_pnp )\r
907         {\r
908                 status = ib_dereg_pnp( gp_dm_agent->h_ca_pnp,\r
909                         (ib_pfn_destroy_cb_t)deref_al_obj );\r
910                 CL_ASSERT( status == IB_SUCCESS );\r
911         }\r
912 }\r
913 \r
914 \r
915 \r
916 /*\r
917  * Free the device management agent.\r
918  */\r
919 void\r
920 free_dm_agent(\r
921         IN                              al_obj_t*                                       p_obj )\r
922 {\r
923         CL_ASSERT( p_obj );\r
924         CL_ASSERT( gp_dm_agent == PARENT_STRUCT( p_obj, dm_agent_t, obj ) );\r
925         UNUSED_PARAM( p_obj );\r
926 \r
927         destroy_al_obj( &gp_dm_agent->obj );\r
928         cl_free( gp_dm_agent );\r
929         gp_dm_agent = NULL;\r
930 }\r
931 \r
932 \r
933 \r
934 /*\r
935  * Register the device management agent for the given PnP class events.\r
936  */\r
937 ib_api_status_t\r
938 dm_agent_reg_pnp(\r
939         IN                              ib_pnp_class_t                          pnp_class,\r
940         IN                              ib_pnp_handle_t*                        ph_pnp )\r
941 {\r
942         ib_api_status_t                 status;\r
943         ib_pnp_req_t                    pnp_req;\r
944 \r
945         CL_ASSERT( ph_pnp );\r
946 \r
947         cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );\r
948         pnp_req.pnp_class       = pnp_class;\r
949         pnp_req.pnp_context = gp_dm_agent;\r
950         pnp_req.pfn_pnp_cb      = dm_agent_pnp_cb;\r
951 \r
952         status = ib_reg_pnp( gh_al, &pnp_req, ph_pnp );\r
953 \r
954         /* Reference the DM agent on behalf of the ib_reg_pnp call. */\r
955         if( status == IB_SUCCESS )\r
956                 ref_al_obj( &gp_dm_agent->obj );\r
957 \r
958         return status;\r
959 }\r
960 \r
961 \r
962 \r
963 /*\r
964  * Device managment agent PnP event callback.\r
965  */\r
966 ib_api_status_t\r
967 dm_agent_pnp_cb(\r
968         IN                              ib_pnp_rec_t*                           p_pnp_rec )\r
969 {\r
970         ib_api_status_t                 status;\r
971         al_iou_t*                               p_iou;\r
972         al_iou_port_t*                  p_iou_port;\r
973 \r
974         CL_ASSERT( p_pnp_rec );\r
975         CL_ASSERT( p_pnp_rec->pnp_context == gp_dm_agent );\r
976 \r
977         /* Dispatch based on the PnP event type. */\r
978         switch( p_pnp_rec->pnp_event )\r
979         {\r
980         case IB_PNP_CA_ADD:\r
981                 status = create_iou( p_pnp_rec );\r
982                 break;\r
983 \r
984         case IB_PNP_CA_REMOVE:\r
985                 CL_ASSERT( p_pnp_rec->context );\r
986                 p_iou = p_pnp_rec->context;\r
987                 ref_al_obj( &p_iou->obj );\r
988                 p_iou->obj.pfn_destroy( &p_iou->obj, NULL );\r
989                 status = IB_SUCCESS;\r
990                 break;\r
991 \r
992         case IB_PNP_PORT_ADD:\r
993                 CL_ASSERT( !p_pnp_rec->context );\r
994                 status = create_iou_port( (ib_pnp_port_rec_t*)p_pnp_rec );\r
995                 break;\r
996 \r
997         case IB_PNP_PORT_REMOVE:\r
998                 CL_ASSERT( p_pnp_rec->context );\r
999                 p_iou_port = p_pnp_rec->context;\r
1000                 ref_al_obj( &p_iou_port->obj );\r
1001                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1002 \r
1003         default:\r
1004                 /* All other events are ignored. */\r
1005                 status = IB_SUCCESS;\r
1006                 break;\r
1007         }\r
1008 \r
1009         return status;\r
1010 }\r
1011 \r
1012 \r
1013 \r
1014 /*\r
1015  * Create an IO unit.\r
1016  */\r
1017 ib_api_status_t\r
1018 create_iou(\r
1019         IN                              ib_pnp_rec_t*                           p_pnp_rec )\r
1020 {\r
1021         al_iou_t*                               p_iou;\r
1022         ib_ca_handle_t                  h_ca;\r
1023         ib_api_status_t                 status;\r
1024 \r
1025         CL_ASSERT( p_pnp_rec );\r
1026 \r
1027         p_iou = cl_zalloc( sizeof( al_iou_t ) );\r
1028         if( !p_iou )\r
1029                 return IB_INSUFFICIENT_MEMORY;\r
1030 \r
1031         /* Construct the IO unit object. */\r
1032         construct_al_obj( &p_iou->obj, AL_OBJ_TYPE_IOU );\r
1033 \r
1034         /* Initialize the IO unit object. */\r
1035         status =\r
1036                 init_al_obj( &p_iou->obj, p_iou, TRUE, NULL, cleanup_iou, free_iou );\r
1037         if( status != IB_SUCCESS )\r
1038         {\r
1039                 free_iou( &p_iou->obj );\r
1040                 return status;\r
1041         }\r
1042 \r
1043         /*\r
1044          * Attach the IO unit to the device management agent.  Lock and\r
1045          * check to synchronize the destruction of the user-mode device\r
1046          * management agent with the creation of the IO unit through a\r
1047          * PnP callback.\r
1048          */\r
1049         cl_spinlock_acquire( &gp_dm_agent->lock );\r
1050         if( gp_dm_agent->destroying )\r
1051         {\r
1052                 p_iou->obj.pfn_destroy( &p_iou->obj, NULL );\r
1053                 cl_spinlock_release( &gp_dm_agent->lock );\r
1054                 return IB_INVALID_STATE;\r
1055         }\r
1056         status = attach_al_obj( &gp_dm_agent->obj, &p_iou->obj );\r
1057         if( status != IB_SUCCESS )\r
1058         {\r
1059                 p_iou->obj.pfn_destroy( &p_iou->obj, NULL );\r
1060                 cl_spinlock_release( &gp_dm_agent->lock );\r
1061                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
1062                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
1063                 return status;\r
1064         }\r
1065         cl_spinlock_release( &gp_dm_agent->lock );\r
1066 \r
1067         /* It is now safe to acquire the CA and initialize the p_ci_ca pointer. */\r
1068         h_ca = acquire_ca( p_pnp_rec->guid );\r
1069         p_iou->obj.p_ci_ca = h_ca->obj.p_ci_ca;\r
1070 \r
1071         /* Initialize the IO unit IOC list. */\r
1072         cl_qlist_init( &p_iou->ioc_list );\r
1073 \r
1074         /* Set the context of the PnP event to this child object. */\r
1075         p_pnp_rec->context = p_iou;\r
1076 \r
1077         /* Release the reference taken in init_al_obj. */\r
1078         deref_al_obj( &p_iou->obj );\r
1079 \r
1080         return IB_SUCCESS;\r
1081 }\r
1082 \r
1083 \r
1084 \r
1085 /*\r
1086  * Cleanup an IO unit.\r
1087  */\r
1088 void\r
1089 cleanup_iou(\r
1090         IN                              al_obj_t*                                       p_obj )\r
1091 {\r
1092         al_iou_t*                               p_iou;\r
1093         cl_list_item_t*                 p_ioc_item;\r
1094         ib_ioc_handle_t                 h_ioc;\r
1095 \r
1096         CL_ASSERT( p_obj );\r
1097         p_iou = PARENT_STRUCT( p_obj, al_iou_t, obj );\r
1098 \r
1099         /* No need to lock during cleanup. */\r
1100         for( p_ioc_item = cl_qlist_remove_head( &p_iou->ioc_list );\r
1101                 p_ioc_item != cl_qlist_end( &p_iou->ioc_list );\r
1102                 p_ioc_item = cl_qlist_remove_head( &p_iou->ioc_list ) )\r
1103         {\r
1104                 h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, obj );\r
1105 \r
1106                 CL_ASSERT( h_ioc->state == EMPTY_SLOT );\r
1107 \r
1108                 /* Detach the IOC from the IO unit. */\r
1109                 CL_ASSERT( h_ioc->p_iou == p_iou );\r
1110                 h_ioc->p_iou = NULL;\r
1111 \r
1112                 /* Destroy the IOC. */\r
1113                 ref_al_obj( &h_ioc->obj );\r
1114                 h_ioc->obj.pfn_destroy( &h_ioc->obj, NULL );\r
1115         }\r
1116 }\r
1117 \r
1118 \r
1119 \r
1120 /*\r
1121  * Free an IO unit.\r
1122  */\r
1123 void\r
1124 free_iou(\r
1125         IN                              al_obj_t*                                       p_obj )\r
1126 {\r
1127         al_iou_t*                               p_iou;\r
1128 \r
1129         CL_ASSERT( p_obj );\r
1130 \r
1131         p_iou = PARENT_STRUCT( p_obj, al_iou_t, obj );\r
1132 \r
1133         /* Dereference the CA. */\r
1134         if( p_iou->obj.p_ci_ca )\r
1135                 deref_al_obj( &p_iou->obj.p_ci_ca->h_ca->obj );\r
1136 \r
1137         destroy_al_obj( &p_iou->obj );\r
1138         cl_free( p_iou );\r
1139 }\r
1140 \r
1141 \r
1142 \r
1143 /*\r
1144  * Create an IO unit port.\r
1145  */\r
1146 ib_api_status_t\r
1147 create_iou_port(\r
1148         IN                              ib_pnp_port_rec_t*                      p_pnp_rec )\r
1149 {\r
1150         al_iou_port_t*                  p_iou_port;\r
1151         al_iou_t*                               p_iou;\r
1152         ib_qp_create_t                  qp_create;\r
1153         ib_mad_svc_t                    mad_svc;\r
1154         ib_api_status_t                 status;\r
1155 \r
1156         CL_ASSERT( p_pnp_rec );\r
1157 \r
1158         CL_ASSERT( p_pnp_rec->p_ca_attr );\r
1159         CL_ASSERT( p_pnp_rec->p_port_attr );\r
1160 \r
1161         p_iou_port = cl_zalloc( sizeof( al_iou_port_t ) );\r
1162         if( !p_iou_port )\r
1163                 return IB_INSUFFICIENT_MEMORY;\r
1164 \r
1165         /* Construct the IO unit port object. */\r
1166         construct_al_obj( &p_iou_port->obj, AL_OBJ_TYPE_IOU );\r
1167 \r
1168         /* Initialize the IO unit port object. */\r
1169         status = init_al_obj( &p_iou_port->obj, p_iou_port, TRUE,\r
1170                 destroying_iou_port, NULL, free_iou_port );\r
1171         if( status != IB_SUCCESS )\r
1172         {\r
1173                 free_iou_port( &p_iou_port->obj );\r
1174                 return status;\r
1175         }\r
1176 \r
1177         /* Acquire the IO unit. */\r
1178         p_iou = acquire_iou( p_pnp_rec->p_ca_attr->ca_guid );\r
1179         if( !p_iou )\r
1180         {\r
1181                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1182                 return IB_INVALID_GUID;\r
1183         }\r
1184 \r
1185         /* Attach the IO unit port to the IO unit. */\r
1186         status = attach_al_obj( &p_iou->obj, &p_iou_port->obj );\r
1187         if( status != IB_SUCCESS )\r
1188         {\r
1189                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1190                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
1191                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
1192                 return status;\r
1193         }\r
1194         deref_al_obj( &p_iou->obj );\r
1195 \r
1196         /* Save the port number. */\r
1197         p_iou_port->port_num = p_pnp_rec->p_port_attr->port_num;\r
1198 \r
1199         /* Save the port GUID - used in svc reg. */\r
1200         p_iou_port->port_guid = p_pnp_rec->pnp_rec.guid;\r
1201 \r
1202         /* Save the default port gid and pkey */\r
1203         p_iou_port->port_gid = p_pnp_rec->p_port_attr->p_gid_table[0];\r
1204         p_iou_port->port_pkey = p_pnp_rec->p_port_attr->p_pkey_table[0];\r
1205 \r
1206         /* Create a QP alias. */\r
1207         cl_memclr( &qp_create, sizeof( ib_qp_create_t ) );\r
1208         qp_create.qp_type               = IB_QPT_QP1_ALIAS;\r
1209         qp_create.sq_depth              = 1;\r
1210         qp_create.sq_sge                = 1;\r
1211         qp_create.sq_signaled   = TRUE;\r
1212 \r
1213         status = ib_get_spl_qp( p_iou_port->obj.p_ci_ca->h_pd_alias,\r
1214                 p_pnp_rec->p_port_attr->port_guid, &qp_create,\r
1215                 p_iou_port, iou_port_event_cb, &p_iou_port->pool_key,\r
1216                 &p_iou_port->h_qp_alias );\r
1217 \r
1218         if (status != IB_SUCCESS)\r
1219         {\r
1220                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1221                 return status;\r
1222         }\r
1223 \r
1224         /* Reference the IO unit port on behalf of ib_get_spl_qp. */\r
1225         ref_al_obj( &p_iou_port->obj );\r
1226 \r
1227         /* Register a service the MAD service for device management. */\r
1228         cl_memclr( &mad_svc, sizeof( ib_mad_svc_t ) );\r
1229         mad_svc.mad_svc_context = p_iou_port;\r
1230         mad_svc.pfn_mad_send_cb = dm_agent_send_cb;\r
1231         mad_svc.pfn_mad_recv_cb = dm_agent_recv_cb;\r
1232         mad_svc.support_unsol   = TRUE;\r
1233         mad_svc.mgmt_class              = IB_MCLASS_DEV_MGMT;\r
1234         mad_svc.mgmt_version    = 1;\r
1235         mad_svc.method_array[ IB_MAD_METHOD_GET ] = TRUE;\r
1236         mad_svc.method_array[ IB_MAD_METHOD_SET ] = TRUE;\r
1237 \r
1238         status = ib_reg_mad_svc( p_iou_port->h_qp_alias, &mad_svc,\r
1239                 &p_iou_port->h_mad_svc );\r
1240         if( status != IB_SUCCESS )\r
1241         {\r
1242                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1243                 return status;\r
1244         }\r
1245 \r
1246         /* Determine if any IOCs are attached to this IO unit. */\r
1247         cl_spinlock_acquire( &p_iou->obj.lock );\r
1248         if( !cl_is_qlist_empty( &p_iou->ioc_list ) )\r
1249         {\r
1250                 /* Set the device management port attribute. */\r
1251                 status = set_port_dm_attr( p_iou_port );\r
1252                 CL_ASSERT( status == IB_SUCCESS );\r
1253         }\r
1254         cl_spinlock_release( &p_iou->obj.lock );\r
1255 \r
1256         /* Set the context of the PnP event to this child object. */\r
1257         p_pnp_rec->pnp_rec.context = p_iou_port;\r
1258 \r
1259         /* Release the reference taken in init_al_obj. */\r
1260         deref_al_obj( &p_iou_port->obj );\r
1261 \r
1262         return IB_SUCCESS;\r
1263 }\r
1264 \r
1265 \r
1266 \r
1267 /*\r
1268  * Pre-destroy an IO unit port.\r
1269  */\r
1270 void\r
1271 destroying_iou_port(\r
1272         IN                              al_obj_t*                                       p_obj )\r
1273 {\r
1274         al_iou_port_t*                  p_iou_port;\r
1275         ib_api_status_t                 status;\r
1276 \r
1277         CL_ASSERT( p_obj );\r
1278         p_iou_port = PARENT_STRUCT( p_obj, al_iou_port_t, obj );\r
1279 \r
1280         /* Deregister the device management service. */\r
1281         if( p_iou_port->svc_handle )\r
1282         {\r
1283                 status = ib_dereg_svc( p_iou_port->svc_handle,\r
1284                         (ib_pfn_destroy_cb_t)deref_al_obj );\r
1285                 CL_ASSERT( status == IB_SUCCESS );\r
1286         }\r
1287 \r
1288         /* Destroy the QP alias. */\r
1289         if( p_iou_port->h_qp_alias )\r
1290         {\r
1291                 status = ib_destroy_qp( p_iou_port->h_qp_alias,\r
1292                         (ib_pfn_destroy_cb_t)deref_al_obj );\r
1293                 CL_ASSERT( status == IB_SUCCESS );\r
1294         }\r
1295 }\r
1296 \r
1297 \r
1298 \r
1299 /*\r
1300  * Free an IO unit port.\r
1301  */\r
1302 void\r
1303 free_iou_port(\r
1304         IN                              al_obj_t*                                       p_obj )\r
1305 {\r
1306         al_iou_port_t*                  p_iou_port;\r
1307 \r
1308         CL_ASSERT( p_obj );\r
1309 \r
1310         p_iou_port = PARENT_STRUCT( p_obj, al_iou_port_t, obj );\r
1311 \r
1312         destroy_al_obj( &p_iou_port->obj );\r
1313         cl_free( p_iou_port );\r
1314 }\r
1315 \r
1316 \r
1317 \r
1318 /*\r
1319  * IO unit port asynchronous event callback.\r
1320  */\r
1321 void\r
1322 iou_port_event_cb(\r
1323         IN                              ib_async_event_rec_t            *p_event_rec )\r
1324 {\r
1325         UNUSED_PARAM( p_event_rec );\r
1326 \r
1327         /* The QP is an alias, so if we've received an error, it is unusable. */\r
1328 }\r
1329 \r
1330 \r
1331 \r
1332 /*\r
1333  * Device management agent send completion callback.\r
1334  */\r
1335 void\r
1336 dm_agent_send_cb(\r
1337         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
1338         IN                              void*                                           mad_svc_context,\r
1339         IN                              ib_mad_element_t*                       p_mad_response )\r
1340 {\r
1341         ib_api_status_t                 status;\r
1342 \r
1343         CL_ASSERT( mad_svc_context );\r
1344         CL_ASSERT( p_mad_response );\r
1345         UNUSED_PARAM( h_mad_svc );\r
1346         UNUSED_PARAM( mad_svc_context );\r
1347 \r
1348         /* Return the MAD. */\r
1349         status = ib_destroy_av( p_mad_response->h_av );\r
1350         CL_ASSERT( status == IB_SUCCESS );\r
1351         status = ib_put_mad( p_mad_response );\r
1352         CL_ASSERT( status == IB_SUCCESS );\r
1353 }\r
1354 \r
1355 \r
1356 \r
1357 /*\r
1358  * Device management agent receive completion callback.\r
1359  */\r
1360 void\r
1361 dm_agent_recv_cb(\r
1362         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
1363         IN                              void*                                           mad_svc_context,\r
1364         IN                              ib_mad_element_t*                       p_mad_request )\r
1365 {\r
1366         al_iou_port_t*                  p_iou_port;\r
1367         ib_mad_element_t*               p_mad_response;\r
1368         ib_mad_t*                               p_mad_req;\r
1369         ib_mad_t*                               p_mad_rsp;\r
1370         ib_av_attr_t                    av_attr;\r
1371         ib_api_status_t                 status;\r
1372 \r
1373         CL_ASSERT( mad_svc_context );\r
1374         CL_ASSERT( p_mad_request );\r
1375 \r
1376         p_iou_port = mad_svc_context;\r
1377         p_mad_req = ib_get_mad_buf( p_mad_request );\r
1378 \r
1379         /* Get a MAD element for the response. */\r
1380         status = ib_get_mad( p_iou_port->pool_key, MAD_BLOCK_SIZE,\r
1381                 &p_mad_response );\r
1382 \r
1383         if( status != IB_SUCCESS )\r
1384         {\r
1385                 status = ib_put_mad( p_mad_request );\r
1386                 CL_ASSERT( status == IB_SUCCESS );\r
1387                 return;\r
1388         }\r
1389 \r
1390         /* Initialize the response MAD element. */\r
1391         p_mad_response->remote_qp       = p_mad_request->remote_qp;\r
1392         p_mad_response->remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY;\r
1393         p_mad_rsp = ib_get_mad_buf( p_mad_response );\r
1394 \r
1395         /* Create an address vector for the response. */\r
1396         cl_memclr( &av_attr, sizeof( ib_av_attr_t ) );\r
1397         av_attr.port_num        = p_iou_port->port_num;\r
1398         av_attr.sl                      = p_mad_request->remote_sl;\r
1399         av_attr.dlid            = p_mad_request->remote_lid;\r
1400         av_attr.path_bits       = p_mad_request->path_bits;\r
1401         av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS;\r
1402         if( p_mad_request->grh_valid )\r
1403         {\r
1404                 av_attr.grh_valid       = TRUE;\r
1405                 av_attr.grh                     = *p_mad_request->p_grh;\r
1406         }\r
1407 \r
1408         status = ib_create_av( p_iou_port->obj.p_ci_ca->h_pd_alias, &av_attr,\r
1409                 &p_mad_response->h_av );\r
1410 \r
1411         if( status != IB_SUCCESS )\r
1412         {\r
1413                 status = ib_put_mad( p_mad_request );\r
1414                 CL_ASSERT( status == IB_SUCCESS );\r
1415                 status = ib_put_mad( p_mad_response );\r
1416                 CL_ASSERT( status == IB_SUCCESS );\r
1417                 return;\r
1418         }\r
1419 \r
1420         /* Initialize the response header. */\r
1421         ib_mad_init_response( p_mad_req, p_mad_rsp, 0 );\r
1422 \r
1423         /* Process the MAD request. */\r
1424         switch( p_mad_req->method )\r
1425         {\r
1426         case IB_MAD_METHOD_GET:\r
1427                 dm_agent_get( p_iou_port, p_mad_req, p_mad_rsp );\r
1428                 break;\r
1429 \r
1430         case IB_MAD_METHOD_SET:\r
1431                 dm_agent_set( p_iou_port, p_mad_req, p_mad_rsp );\r
1432                 break;\r
1433 \r
1434         default:\r
1435                 p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD;\r
1436                 break;\r
1437         }\r
1438 \r
1439         /* Return the request to the pool. */\r
1440         status = ib_put_mad( p_mad_request );\r
1441         CL_ASSERT( status == IB_SUCCESS );\r
1442 \r
1443         /* Send the response. */\r
1444         status = ib_send_mad( h_mad_svc, p_mad_response, NULL );\r
1445 \r
1446         if( status != IB_SUCCESS )\r
1447         {\r
1448                 status = ib_destroy_av( p_mad_response->h_av );\r
1449                 CL_ASSERT( status == IB_SUCCESS );\r
1450                 status = ib_put_mad( p_mad_response );\r
1451                 CL_ASSERT( status == IB_SUCCESS );\r
1452         }\r
1453 }\r
1454 \r
1455 \r
1456 \r
1457 /*\r
1458  * Device management agent get method MAD.\r
1459  */\r
1460 void\r
1461 dm_agent_get(\r
1462         IN                              al_iou_port_t*                          p_iou_port,\r
1463         IN                              ib_mad_t*                                       p_mad_req,\r
1464         IN                              ib_mad_t*                                       p_mad_rsp )\r
1465 {\r
1466         al_iou_t*                               p_iou;\r
1467         ib_dm_mad_t*                    p_dm_mad;\r
1468 \r
1469         CL_ASSERT( p_iou_port );\r
1470         CL_ASSERT( p_mad_req );\r
1471         CL_ASSERT( p_mad_rsp );\r
1472 \r
1473         p_iou = PARENT_STRUCT( p_iou_port->obj.p_parent_obj, al_iou_t, obj );\r
1474 \r
1475         p_dm_mad = (ib_dm_mad_t*)p_mad_rsp;\r
1476 \r
1477         switch( p_mad_req->attr_id )\r
1478         {\r
1479         case IB_MAD_ATTR_CLASS_PORT_INFO:\r
1480                 get_class_port_info( p_iou, p_dm_mad );\r
1481                 break;\r
1482 \r
1483         case IB_MAD_ATTR_IO_UNIT_INFO:\r
1484                 get_io_unit_info( p_iou, p_dm_mad );\r
1485                 break;\r
1486 \r
1487         case IB_MAD_ATTR_IOC_PROFILE:\r
1488         {\r
1489                 uint8_t         slot;\r
1490 \r
1491                 slot = (uint8_t)CL_NTOH32( p_dm_mad->hdr.attr_mod );\r
1492 \r
1493                 get_ioc_profile( p_iou, slot, p_dm_mad );\r
1494                 break;\r
1495         }\r
1496 \r
1497         case IB_MAD_ATTR_SERVICE_ENTRIES:\r
1498         {\r
1499                 uint8_t         slot;\r
1500                 uint8_t         svc_num_hi;\r
1501                 uint8_t         svc_num_lo;\r
1502 \r
1503                 ib_dm_get_slot_lo_hi( p_dm_mad->hdr.attr_mod, &slot,\r
1504                         &svc_num_hi, &svc_num_lo );\r
1505 \r
1506                 get_svc_entries( p_iou, slot, svc_num_lo, svc_num_hi, p_dm_mad );\r
1507                 break;\r
1508         }\r
1509 \r
1510         case IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT:\r
1511         case IB_MAD_ATTR_PREPARE_TO_TEST:\r
1512         case IB_MAD_ATTR_DIAG_CODE:\r
1513         default:\r
1514                 p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD_ATTR;\r
1515                 break;\r
1516         }\r
1517 }\r
1518 \r
1519 \r
1520 \r
1521 /*\r
1522  * Device management agent set method MAD.\r
1523  */\r
1524 void\r
1525 dm_agent_set(\r
1526         IN                              al_iou_port_t*                          p_iou_port,\r
1527         IN                              ib_mad_t*                                       p_mad_req,\r
1528         IN                              ib_mad_t*                                       p_mad_rsp )\r
1529 {\r
1530         ib_dm_mad_t*                    p_dm_mad;\r
1531 \r
1532         CL_ASSERT( p_iou_port );\r
1533         CL_ASSERT( p_mad_req );\r
1534         CL_ASSERT( p_mad_rsp );\r
1535         UNUSED_PARAM( p_iou_port );\r
1536 \r
1537         p_dm_mad = (ib_dm_mad_t*)p_mad_rsp;\r
1538 \r
1539         switch( p_mad_req->attr_id )\r
1540         {\r
1541         case IB_MAD_ATTR_CLASS_PORT_INFO:\r
1542                 break;\r
1543 \r
1544         case IB_MAD_ATTR_PREPARE_TO_TEST:\r
1545         case IB_MAD_ATTR_TEST_DEVICE_ONCE:\r
1546         case IB_MAD_ATTR_TEST_DEVICE_LOOP:\r
1547         default:\r
1548                 p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD_ATTR;\r
1549                 break;\r
1550         }\r
1551 }\r
1552 \r
1553 \r
1554 void\r
1555 get_class_port_info(\r
1556         IN                              al_iou_t*                                       p_iou,\r
1557         IN                              ib_dm_mad_t*                            p_dm_mad )\r
1558 {\r
1559         ib_class_port_info_t*   p_class_port_info;\r
1560 \r
1561         CL_ASSERT( p_iou );\r
1562         CL_ASSERT( p_dm_mad );\r
1563         UNUSED_PARAM( p_iou );\r
1564 \r
1565         p_class_port_info = (ib_class_port_info_t*)&p_dm_mad->data;\r
1566 \r
1567         p_class_port_info->base_ver      = 1;\r
1568         p_class_port_info->class_ver = 1;\r
1569         p_class_port_info->resp_time_val = CL_HTON32( DM_CLASS_RESP_TIME_VALUE );\r
1570 }\r
1571 \r
1572 \r
1573 \r
1574 void\r
1575 get_io_unit_info(\r
1576         IN                              al_iou_t*                                       p_iou,\r
1577         IN                              ib_dm_mad_t*                            p_dm_mad )\r
1578 {\r
1579         ib_iou_info_t*                  p_iou_info;\r
1580         cl_list_item_t*                 p_ioc_item;\r
1581         ib_ioc_handle_t                 h_ioc;\r
1582         uint8_t                                 slot;\r
1583 \r
1584         CL_ASSERT( p_iou );\r
1585         CL_ASSERT( p_dm_mad );\r
1586 \r
1587         p_iou_info = (ib_iou_info_t*)&p_dm_mad->data;\r
1588 \r
1589         cl_spinlock_acquire( &p_iou->obj.lock );\r
1590 \r
1591         p_iou_info->change_id = p_iou->change_id;\r
1592 \r
1593         /* Mark all slots as non-existant. */\r
1594         SET_NIBBLE( &slot, 0, SLOT_DOES_NOT_EXIST );\r
1595         SET_NIBBLE( &slot, 1, SLOT_DOES_NOT_EXIST );\r
1596         cl_memset( p_iou_info->controller_list, slot, sizeof( p_iou->ioc_list ) );\r
1597 \r
1598         /* Now mark the existing slots. */\r
1599         slot = 1;\r
1600         for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list );\r
1601                  p_ioc_item != cl_qlist_end( &p_iou->ioc_list );\r
1602                  p_ioc_item = cl_qlist_next( p_ioc_item ) )\r
1603         {\r
1604                 h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item );\r
1605 \r
1606                 switch( h_ioc->state )\r
1607                 {\r
1608                 case EMPTY_SLOT:\r
1609                 case SLOT_IN_USE:\r
1610                         SET_NIBBLE( p_iou_info->controller_list, slot, IOC_NOT_INSTALLED );\r
1611                         break;\r
1612 \r
1613                 case IOC_ACTIVE:\r
1614                         SET_NIBBLE( p_iou_info->controller_list, slot, IOC_INSTALLED );\r
1615                         break;\r
1616 \r
1617                 default:\r
1618                         break;\r
1619                 }\r
1620                 slot++;\r
1621         }\r
1622 \r
1623         p_iou_info->max_controllers = slot;\r
1624 \r
1625         cl_spinlock_release( &p_iou->obj.lock );\r
1626 }\r
1627 \r
1628 \r
1629 \r
1630 void\r
1631 get_ioc_profile(\r
1632         IN                              al_iou_t*                                       p_iou,\r
1633         IN                              uint8_t                                         slot,\r
1634         IN                              ib_dm_mad_t*                            p_dm_mad )\r
1635 {\r
1636         ib_ioc_profile_t*               p_ioc_profile;\r
1637         cl_list_item_t*                 p_ioc_item;\r
1638         ib_ioc_handle_t                 h_ioc;\r
1639 \r
1640         CL_ASSERT( p_iou );\r
1641         CL_ASSERT( p_dm_mad );\r
1642 \r
1643         p_ioc_profile = (ib_ioc_profile_t*)&p_dm_mad->data;\r
1644 \r
1645         cl_spinlock_acquire( &p_iou->obj.lock );\r
1646 \r
1647         /* Verify that the slot number is within range. */\r
1648         if( ( slot == 0 ) ||\r
1649                 ( slot > cl_qlist_count( &p_iou->ioc_list ) ) )\r
1650         {\r
1651                 cl_spinlock_release( &p_iou->obj.lock );\r
1652                 p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD;\r
1653                 return;\r
1654         }\r
1655 \r
1656         /* The remaining code assumes the slot number starts at zero. */\r
1657         for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list );\r
1658                  p_ioc_item != cl_qlist_end( &p_iou->ioc_list ) && slot;\r
1659                  p_ioc_item = cl_qlist_next( p_ioc_item ) )\r
1660         {\r
1661                 slot--;\r
1662         }\r
1663 \r
1664         h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item );\r
1665 \r
1666         cl_spinlock_acquire( &h_ioc->obj.lock );\r
1667 \r
1668         /* Verify the IOC state. */\r
1669         if( h_ioc->state != IOC_ACTIVE )\r
1670         {\r
1671                 cl_spinlock_release( &h_ioc->obj.lock );\r
1672                 cl_spinlock_release( &p_iou->obj.lock );\r
1673                 p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_IOC_RESP;\r
1674                 return;\r
1675         }\r
1676 \r
1677         /* Copy the IOC profile. */\r
1678         *p_ioc_profile = h_ioc->ioc_profile;\r
1679 \r
1680         cl_spinlock_release( &h_ioc->obj.lock );\r
1681         cl_spinlock_release( &p_iou->obj.lock );\r
1682 }\r
1683 \r
1684 \r
1685 \r
1686 void\r
1687 get_svc_entries(\r
1688         IN                              al_iou_t*                                       p_iou,\r
1689         IN                              uint8_t                                         slot,\r
1690         IN                              uint8_t                                         svc_num_lo,\r
1691         IN                              uint8_t                                         svc_num_hi,\r
1692         IN                              ib_dm_mad_t*                            p_dm_mad )\r
1693 {\r
1694         ib_svc_entries_t*               p_svc_entries;\r
1695         cl_list_item_t*                 p_ioc_item;\r
1696         cl_list_item_t*                 p_list_item;\r
1697         ib_ioc_handle_t                 h_ioc;\r
1698         al_obj_t*                               p_obj;\r
1699         al_svc_entry_t*                 p_svc_entry;\r
1700         uint8_t                                 i, j, k;\r
1701 \r
1702         CL_ASSERT( p_iou );\r
1703         CL_ASSERT( p_dm_mad );\r
1704 \r
1705         p_svc_entries = (ib_svc_entries_t*)&p_dm_mad->data;\r
1706 \r
1707         cl_spinlock_acquire( &p_iou->obj.lock );\r
1708 \r
1709         /*\r
1710          * Verify that the slot number is within range and\r
1711          * a maximum of SVC_ENTRY_COUNT entries is requested.\r
1712          */\r
1713         if( ( slot == 0 ) ||\r
1714                 ( slot > cl_qlist_count( &p_iou->ioc_list ) ) ||\r
1715                 ( ( svc_num_hi - svc_num_lo + 1) > SVC_ENTRY_COUNT ) )\r
1716         {\r
1717                 cl_spinlock_release( &p_iou->obj.lock );\r
1718                 p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD;\r
1719                 return;\r
1720         }\r
1721 \r
1722         /* The remaining code assumes the slot number starts at zero. */\r
1723         for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list );\r
1724                  p_ioc_item != cl_qlist_end( &p_iou->ioc_list ) && slot;\r
1725                  p_ioc_item = cl_qlist_next( p_ioc_item ) )\r
1726         {\r
1727                 slot--;\r
1728         }\r
1729 \r
1730         h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item );\r
1731 \r
1732         cl_spinlock_acquire( &h_ioc->obj.lock );\r
1733 \r
1734         /* Verify the IOC state. */\r
1735         if( h_ioc->state != IOC_ACTIVE )\r
1736         {\r
1737                 cl_spinlock_release( &h_ioc->obj.lock );\r
1738                 cl_spinlock_release( &p_iou->obj.lock );\r
1739                 p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_IOC_RESP;\r
1740                 return;\r
1741         }\r
1742 \r
1743         /* Verify the service entry range. */\r
1744         if( ( svc_num_lo > h_ioc->ioc_profile.num_svc_entries ) ||\r
1745                 ( svc_num_hi >= h_ioc->ioc_profile.num_svc_entries ) )\r
1746         {\r
1747                 cl_spinlock_release( &h_ioc->obj.lock );\r
1748                 cl_spinlock_release( &p_iou->obj.lock );\r
1749                 p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD;\r
1750                 return;\r
1751         }\r
1752 \r
1753         for( i = svc_num_lo, j = 0; j < ( svc_num_hi - svc_num_lo + 1 ); i++, j++ )\r
1754         {\r
1755                 k = i;\r
1756 \r
1757                 /* Locate the service entry. Traverse until k=0. */\r
1758                 for( p_list_item = cl_qlist_head( &h_ioc->obj.obj_list );\r
1759                          k && ( p_list_item != cl_qlist_end( &h_ioc->obj.obj_list ) );\r
1760                          p_list_item = cl_qlist_next( p_list_item ) )\r
1761                 {\r
1762                         k--;\r
1763                 }\r
1764 \r
1765                 if( p_list_item == cl_qlist_end( &h_ioc->obj.obj_list ) )\r
1766                 {\r
1767                         /* The service entry list was empty or the end was reached. */\r
1768                         cl_spinlock_release( &h_ioc->obj.lock );\r
1769                         cl_spinlock_release( &p_iou->obj.lock );\r
1770                         p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_SVC_ENTRIES;\r
1771                         return;\r
1772                 }\r
1773 \r
1774                 p_obj = PARENT_STRUCT( p_list_item, al_obj_t, obj_list );\r
1775                 p_svc_entry = PARENT_STRUCT( p_obj, al_svc_entry_t, obj );\r
1776 \r
1777                 /* Copy the service entry. */\r
1778                 p_svc_entries->service_entry[ j ] = p_svc_entry->svc_entry;\r
1779         }\r
1780 \r
1781         cl_spinlock_release( &h_ioc->obj.lock );\r
1782         cl_spinlock_release( &p_iou->obj.lock );\r
1783 }\r