[IBAL] Handle acquire_ca failing in create_iou
[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         if( !h_ca )\r
1070         {\r
1071                 p_iou->obj.pfn_destroy( &p_iou->obj, NULL );\r
1072                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
1073                         ("acquire_ca for GUID %016I64x failed.\n", p_pnp_rec->guid) );\r
1074                 return IB_INVALID_CA_HANDLE;\r
1075         }\r
1076 \r
1077         p_iou->obj.p_ci_ca = h_ca->obj.p_ci_ca;\r
1078 \r
1079         /* Initialize the IO unit IOC list. */\r
1080         cl_qlist_init( &p_iou->ioc_list );\r
1081 \r
1082         /* Set the context of the PnP event to this child object. */\r
1083         p_pnp_rec->context = p_iou;\r
1084 \r
1085         /* Release the reference taken in init_al_obj. */\r
1086         deref_al_obj( &p_iou->obj );\r
1087 \r
1088         return IB_SUCCESS;\r
1089 }\r
1090 \r
1091 \r
1092 \r
1093 /*\r
1094  * Cleanup an IO unit.\r
1095  */\r
1096 void\r
1097 cleanup_iou(\r
1098         IN                              al_obj_t*                                       p_obj )\r
1099 {\r
1100         al_iou_t*                               p_iou;\r
1101         cl_list_item_t*                 p_ioc_item;\r
1102         ib_ioc_handle_t                 h_ioc;\r
1103 \r
1104         CL_ASSERT( p_obj );\r
1105         p_iou = PARENT_STRUCT( p_obj, al_iou_t, obj );\r
1106 \r
1107         /* No need to lock during cleanup. */\r
1108         for( p_ioc_item = cl_qlist_remove_head( &p_iou->ioc_list );\r
1109                 p_ioc_item != cl_qlist_end( &p_iou->ioc_list );\r
1110                 p_ioc_item = cl_qlist_remove_head( &p_iou->ioc_list ) )\r
1111         {\r
1112                 h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, obj );\r
1113 \r
1114                 CL_ASSERT( h_ioc->state == EMPTY_SLOT );\r
1115 \r
1116                 /* Detach the IOC from the IO unit. */\r
1117                 CL_ASSERT( h_ioc->p_iou == p_iou );\r
1118                 h_ioc->p_iou = NULL;\r
1119 \r
1120                 /* Destroy the IOC. */\r
1121                 ref_al_obj( &h_ioc->obj );\r
1122                 h_ioc->obj.pfn_destroy( &h_ioc->obj, NULL );\r
1123         }\r
1124 }\r
1125 \r
1126 \r
1127 \r
1128 /*\r
1129  * Free an IO unit.\r
1130  */\r
1131 void\r
1132 free_iou(\r
1133         IN                              al_obj_t*                                       p_obj )\r
1134 {\r
1135         al_iou_t*                               p_iou;\r
1136 \r
1137         CL_ASSERT( p_obj );\r
1138 \r
1139         p_iou = PARENT_STRUCT( p_obj, al_iou_t, obj );\r
1140 \r
1141         /* Dereference the CA. */\r
1142         if( p_iou->obj.p_ci_ca )\r
1143                 deref_al_obj( &p_iou->obj.p_ci_ca->h_ca->obj );\r
1144 \r
1145         destroy_al_obj( &p_iou->obj );\r
1146         cl_free( p_iou );\r
1147 }\r
1148 \r
1149 \r
1150 \r
1151 /*\r
1152  * Create an IO unit port.\r
1153  */\r
1154 ib_api_status_t\r
1155 create_iou_port(\r
1156         IN                              ib_pnp_port_rec_t*                      p_pnp_rec )\r
1157 {\r
1158         al_iou_port_t*                  p_iou_port;\r
1159         al_iou_t*                               p_iou;\r
1160         ib_qp_create_t                  qp_create;\r
1161         ib_mad_svc_t                    mad_svc;\r
1162         ib_api_status_t                 status;\r
1163 \r
1164         CL_ASSERT( p_pnp_rec );\r
1165 \r
1166         CL_ASSERT( p_pnp_rec->p_ca_attr );\r
1167         CL_ASSERT( p_pnp_rec->p_port_attr );\r
1168 \r
1169         p_iou_port = cl_zalloc( sizeof( al_iou_port_t ) );\r
1170         if( !p_iou_port )\r
1171                 return IB_INSUFFICIENT_MEMORY;\r
1172 \r
1173         /* Construct the IO unit port object. */\r
1174         construct_al_obj( &p_iou_port->obj, AL_OBJ_TYPE_IOU );\r
1175 \r
1176         /* Initialize the IO unit port object. */\r
1177         status = init_al_obj( &p_iou_port->obj, p_iou_port, TRUE,\r
1178                 destroying_iou_port, NULL, free_iou_port );\r
1179         if( status != IB_SUCCESS )\r
1180         {\r
1181                 free_iou_port( &p_iou_port->obj );\r
1182                 return status;\r
1183         }\r
1184 \r
1185         /* Acquire the IO unit. */\r
1186         p_iou = acquire_iou( p_pnp_rec->p_ca_attr->ca_guid );\r
1187         if( !p_iou )\r
1188         {\r
1189                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1190                 return IB_INVALID_GUID;\r
1191         }\r
1192 \r
1193         /* Attach the IO unit port to the IO unit. */\r
1194         status = attach_al_obj( &p_iou->obj, &p_iou_port->obj );\r
1195         if( status != IB_SUCCESS )\r
1196         {\r
1197                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1198                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
1199                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
1200                 return status;\r
1201         }\r
1202         deref_al_obj( &p_iou->obj );\r
1203 \r
1204         /* Save the port number. */\r
1205         p_iou_port->port_num = p_pnp_rec->p_port_attr->port_num;\r
1206 \r
1207         /* Save the port GUID - used in svc reg. */\r
1208         p_iou_port->port_guid = p_pnp_rec->pnp_rec.guid;\r
1209 \r
1210         /* Save the default port gid and pkey */\r
1211         p_iou_port->port_gid = p_pnp_rec->p_port_attr->p_gid_table[0];\r
1212         p_iou_port->port_pkey = p_pnp_rec->p_port_attr->p_pkey_table[0];\r
1213 \r
1214         /* Create a QP alias. */\r
1215         cl_memclr( &qp_create, sizeof( ib_qp_create_t ) );\r
1216         qp_create.qp_type               = IB_QPT_QP1_ALIAS;\r
1217         qp_create.sq_depth              = 1;\r
1218         qp_create.sq_sge                = 1;\r
1219         qp_create.sq_signaled   = TRUE;\r
1220 \r
1221         status = ib_get_spl_qp( p_iou_port->obj.p_ci_ca->h_pd_alias,\r
1222                 p_pnp_rec->p_port_attr->port_guid, &qp_create,\r
1223                 p_iou_port, iou_port_event_cb, &p_iou_port->pool_key,\r
1224                 &p_iou_port->h_qp_alias );\r
1225 \r
1226         if (status != IB_SUCCESS)\r
1227         {\r
1228                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1229                 return status;\r
1230         }\r
1231 \r
1232         /* Reference the IO unit port on behalf of ib_get_spl_qp. */\r
1233         ref_al_obj( &p_iou_port->obj );\r
1234 \r
1235         /* Register a service the MAD service for device management. */\r
1236         cl_memclr( &mad_svc, sizeof( ib_mad_svc_t ) );\r
1237         mad_svc.mad_svc_context = p_iou_port;\r
1238         mad_svc.pfn_mad_send_cb = dm_agent_send_cb;\r
1239         mad_svc.pfn_mad_recv_cb = dm_agent_recv_cb;\r
1240         mad_svc.support_unsol   = TRUE;\r
1241         mad_svc.mgmt_class              = IB_MCLASS_DEV_MGMT;\r
1242         mad_svc.mgmt_version    = 1;\r
1243         mad_svc.method_array[ IB_MAD_METHOD_GET ] = TRUE;\r
1244         mad_svc.method_array[ IB_MAD_METHOD_SET ] = TRUE;\r
1245 \r
1246         status = ib_reg_mad_svc( p_iou_port->h_qp_alias, &mad_svc,\r
1247                 &p_iou_port->h_mad_svc );\r
1248         if( status != IB_SUCCESS )\r
1249         {\r
1250                 p_iou_port->obj.pfn_destroy( &p_iou_port->obj, NULL );\r
1251                 return status;\r
1252         }\r
1253 \r
1254         /* Determine if any IOCs are attached to this IO unit. */\r
1255         cl_spinlock_acquire( &p_iou->obj.lock );\r
1256         if( !cl_is_qlist_empty( &p_iou->ioc_list ) )\r
1257         {\r
1258                 /* Set the device management port attribute. */\r
1259                 status = set_port_dm_attr( p_iou_port );\r
1260                 CL_ASSERT( status == IB_SUCCESS );\r
1261         }\r
1262         cl_spinlock_release( &p_iou->obj.lock );\r
1263 \r
1264         /* Set the context of the PnP event to this child object. */\r
1265         p_pnp_rec->pnp_rec.context = p_iou_port;\r
1266 \r
1267         /* Release the reference taken in init_al_obj. */\r
1268         deref_al_obj( &p_iou_port->obj );\r
1269 \r
1270         return IB_SUCCESS;\r
1271 }\r
1272 \r
1273 \r
1274 \r
1275 /*\r
1276  * Pre-destroy an IO unit port.\r
1277  */\r
1278 void\r
1279 destroying_iou_port(\r
1280         IN                              al_obj_t*                                       p_obj )\r
1281 {\r
1282         al_iou_port_t*                  p_iou_port;\r
1283         ib_api_status_t                 status;\r
1284 \r
1285         CL_ASSERT( p_obj );\r
1286         p_iou_port = PARENT_STRUCT( p_obj, al_iou_port_t, obj );\r
1287 \r
1288         /* Deregister the device management service. */\r
1289         if( p_iou_port->svc_handle )\r
1290         {\r
1291                 status = ib_dereg_svc( p_iou_port->svc_handle,\r
1292                         (ib_pfn_destroy_cb_t)deref_al_obj );\r
1293                 CL_ASSERT( status == IB_SUCCESS );\r
1294         }\r
1295 \r
1296         /* Destroy the QP alias. */\r
1297         if( p_iou_port->h_qp_alias )\r
1298         {\r
1299                 status = ib_destroy_qp( p_iou_port->h_qp_alias,\r
1300                         (ib_pfn_destroy_cb_t)deref_al_obj );\r
1301                 CL_ASSERT( status == IB_SUCCESS );\r
1302         }\r
1303 }\r
1304 \r
1305 \r
1306 \r
1307 /*\r
1308  * Free an IO unit port.\r
1309  */\r
1310 void\r
1311 free_iou_port(\r
1312         IN                              al_obj_t*                                       p_obj )\r
1313 {\r
1314         al_iou_port_t*                  p_iou_port;\r
1315 \r
1316         CL_ASSERT( p_obj );\r
1317 \r
1318         p_iou_port = PARENT_STRUCT( p_obj, al_iou_port_t, obj );\r
1319 \r
1320         destroy_al_obj( &p_iou_port->obj );\r
1321         cl_free( p_iou_port );\r
1322 }\r
1323 \r
1324 \r
1325 \r
1326 /*\r
1327  * IO unit port asynchronous event callback.\r
1328  */\r
1329 void\r
1330 iou_port_event_cb(\r
1331         IN                              ib_async_event_rec_t            *p_event_rec )\r
1332 {\r
1333         UNUSED_PARAM( p_event_rec );\r
1334 \r
1335         /* The QP is an alias, so if we've received an error, it is unusable. */\r
1336 }\r
1337 \r
1338 \r
1339 \r
1340 /*\r
1341  * Device management agent send completion callback.\r
1342  */\r
1343 void\r
1344 dm_agent_send_cb(\r
1345         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
1346         IN                              void*                                           mad_svc_context,\r
1347         IN                              ib_mad_element_t*                       p_mad_response )\r
1348 {\r
1349         ib_api_status_t                 status;\r
1350 \r
1351         CL_ASSERT( mad_svc_context );\r
1352         CL_ASSERT( p_mad_response );\r
1353         UNUSED_PARAM( h_mad_svc );\r
1354         UNUSED_PARAM( mad_svc_context );\r
1355 \r
1356         /* Return the MAD. */\r
1357         status = ib_destroy_av( p_mad_response->h_av );\r
1358         CL_ASSERT( status == IB_SUCCESS );\r
1359         status = ib_put_mad( p_mad_response );\r
1360         CL_ASSERT( status == IB_SUCCESS );\r
1361 }\r
1362 \r
1363 \r
1364 \r
1365 /*\r
1366  * Device management agent receive completion callback.\r
1367  */\r
1368 void\r
1369 dm_agent_recv_cb(\r
1370         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
1371         IN                              void*                                           mad_svc_context,\r
1372         IN                              ib_mad_element_t*                       p_mad_request )\r
1373 {\r
1374         al_iou_port_t*                  p_iou_port;\r
1375         ib_mad_element_t*               p_mad_response;\r
1376         ib_mad_t*                               p_mad_req;\r
1377         ib_mad_t*                               p_mad_rsp;\r
1378         ib_av_attr_t                    av_attr;\r
1379         ib_api_status_t                 status;\r
1380 \r
1381         CL_ASSERT( mad_svc_context );\r
1382         CL_ASSERT( p_mad_request );\r
1383 \r
1384         p_iou_port = mad_svc_context;\r
1385         p_mad_req = ib_get_mad_buf( p_mad_request );\r
1386 \r
1387         /* Get a MAD element for the response. */\r
1388         status = ib_get_mad( p_iou_port->pool_key, MAD_BLOCK_SIZE,\r
1389                 &p_mad_response );\r
1390 \r
1391         if( status != IB_SUCCESS )\r
1392         {\r
1393                 status = ib_put_mad( p_mad_request );\r
1394                 CL_ASSERT( status == IB_SUCCESS );\r
1395                 return;\r
1396         }\r
1397 \r
1398         /* Initialize the response MAD element. */\r
1399         p_mad_response->remote_qp       = p_mad_request->remote_qp;\r
1400         p_mad_response->remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY;\r
1401         p_mad_rsp = ib_get_mad_buf( p_mad_response );\r
1402 \r
1403         /* Create an address vector for the response. */\r
1404         cl_memclr( &av_attr, sizeof( ib_av_attr_t ) );\r
1405         av_attr.port_num        = p_iou_port->port_num;\r
1406         av_attr.sl                      = p_mad_request->remote_sl;\r
1407         av_attr.dlid            = p_mad_request->remote_lid;\r
1408         av_attr.path_bits       = p_mad_request->path_bits;\r
1409         av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS;\r
1410         if( p_mad_request->grh_valid )\r
1411         {\r
1412                 av_attr.grh_valid       = TRUE;\r
1413                 av_attr.grh                     = *p_mad_request->p_grh;\r
1414         }\r
1415 \r
1416         status = ib_create_av( p_iou_port->obj.p_ci_ca->h_pd_alias, &av_attr,\r
1417                 &p_mad_response->h_av );\r
1418 \r
1419         if( status != IB_SUCCESS )\r
1420         {\r
1421                 status = ib_put_mad( p_mad_request );\r
1422                 CL_ASSERT( status == IB_SUCCESS );\r
1423                 status = ib_put_mad( p_mad_response );\r
1424                 CL_ASSERT( status == IB_SUCCESS );\r
1425                 return;\r
1426         }\r
1427 \r
1428         /* Initialize the response header. */\r
1429         ib_mad_init_response( p_mad_req, p_mad_rsp, 0 );\r
1430 \r
1431         /* Process the MAD request. */\r
1432         switch( p_mad_req->method )\r
1433         {\r
1434         case IB_MAD_METHOD_GET:\r
1435                 dm_agent_get( p_iou_port, p_mad_req, p_mad_rsp );\r
1436                 break;\r
1437 \r
1438         case IB_MAD_METHOD_SET:\r
1439                 dm_agent_set( p_iou_port, p_mad_req, p_mad_rsp );\r
1440                 break;\r
1441 \r
1442         default:\r
1443                 p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD;\r
1444                 break;\r
1445         }\r
1446 \r
1447         /* Return the request to the pool. */\r
1448         status = ib_put_mad( p_mad_request );\r
1449         CL_ASSERT( status == IB_SUCCESS );\r
1450 \r
1451         /* Send the response. */\r
1452         status = ib_send_mad( h_mad_svc, p_mad_response, NULL );\r
1453 \r
1454         if( status != IB_SUCCESS )\r
1455         {\r
1456                 status = ib_destroy_av( p_mad_response->h_av );\r
1457                 CL_ASSERT( status == IB_SUCCESS );\r
1458                 status = ib_put_mad( p_mad_response );\r
1459                 CL_ASSERT( status == IB_SUCCESS );\r
1460         }\r
1461 }\r
1462 \r
1463 \r
1464 \r
1465 /*\r
1466  * Device management agent get method MAD.\r
1467  */\r
1468 void\r
1469 dm_agent_get(\r
1470         IN                              al_iou_port_t*                          p_iou_port,\r
1471         IN                              ib_mad_t*                                       p_mad_req,\r
1472         IN                              ib_mad_t*                                       p_mad_rsp )\r
1473 {\r
1474         al_iou_t*                               p_iou;\r
1475         ib_dm_mad_t*                    p_dm_mad;\r
1476 \r
1477         CL_ASSERT( p_iou_port );\r
1478         CL_ASSERT( p_mad_req );\r
1479         CL_ASSERT( p_mad_rsp );\r
1480 \r
1481         p_iou = PARENT_STRUCT( p_iou_port->obj.p_parent_obj, al_iou_t, obj );\r
1482 \r
1483         p_dm_mad = (ib_dm_mad_t*)p_mad_rsp;\r
1484 \r
1485         switch( p_mad_req->attr_id )\r
1486         {\r
1487         case IB_MAD_ATTR_CLASS_PORT_INFO:\r
1488                 get_class_port_info( p_iou, p_dm_mad );\r
1489                 break;\r
1490 \r
1491         case IB_MAD_ATTR_IO_UNIT_INFO:\r
1492                 get_io_unit_info( p_iou, p_dm_mad );\r
1493                 break;\r
1494 \r
1495         case IB_MAD_ATTR_IOC_PROFILE:\r
1496         {\r
1497                 uint8_t         slot;\r
1498 \r
1499                 slot = (uint8_t)CL_NTOH32( p_dm_mad->hdr.attr_mod );\r
1500 \r
1501                 get_ioc_profile( p_iou, slot, p_dm_mad );\r
1502                 break;\r
1503         }\r
1504 \r
1505         case IB_MAD_ATTR_SERVICE_ENTRIES:\r
1506         {\r
1507                 uint8_t         slot;\r
1508                 uint8_t         svc_num_hi;\r
1509                 uint8_t         svc_num_lo;\r
1510 \r
1511                 ib_dm_get_slot_lo_hi( p_dm_mad->hdr.attr_mod, &slot,\r
1512                         &svc_num_hi, &svc_num_lo );\r
1513 \r
1514                 get_svc_entries( p_iou, slot, svc_num_lo, svc_num_hi, p_dm_mad );\r
1515                 break;\r
1516         }\r
1517 \r
1518         case IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT:\r
1519         case IB_MAD_ATTR_PREPARE_TO_TEST:\r
1520         case IB_MAD_ATTR_DIAG_CODE:\r
1521         default:\r
1522                 p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD_ATTR;\r
1523                 break;\r
1524         }\r
1525 }\r
1526 \r
1527 \r
1528 \r
1529 /*\r
1530  * Device management agent set method MAD.\r
1531  */\r
1532 void\r
1533 dm_agent_set(\r
1534         IN                              al_iou_port_t*                          p_iou_port,\r
1535         IN                              ib_mad_t*                                       p_mad_req,\r
1536         IN                              ib_mad_t*                                       p_mad_rsp )\r
1537 {\r
1538         ib_dm_mad_t*                    p_dm_mad;\r
1539 \r
1540         CL_ASSERT( p_iou_port );\r
1541         CL_ASSERT( p_mad_req );\r
1542         CL_ASSERT( p_mad_rsp );\r
1543         UNUSED_PARAM( p_iou_port );\r
1544 \r
1545         p_dm_mad = (ib_dm_mad_t*)p_mad_rsp;\r
1546 \r
1547         switch( p_mad_req->attr_id )\r
1548         {\r
1549         case IB_MAD_ATTR_CLASS_PORT_INFO:\r
1550                 break;\r
1551 \r
1552         case IB_MAD_ATTR_PREPARE_TO_TEST:\r
1553         case IB_MAD_ATTR_TEST_DEVICE_ONCE:\r
1554         case IB_MAD_ATTR_TEST_DEVICE_LOOP:\r
1555         default:\r
1556                 p_mad_rsp->status = IB_MAD_STATUS_UNSUP_METHOD_ATTR;\r
1557                 break;\r
1558         }\r
1559 }\r
1560 \r
1561 \r
1562 void\r
1563 get_class_port_info(\r
1564         IN                              al_iou_t*                                       p_iou,\r
1565         IN                              ib_dm_mad_t*                            p_dm_mad )\r
1566 {\r
1567         ib_class_port_info_t*   p_class_port_info;\r
1568 \r
1569         CL_ASSERT( p_iou );\r
1570         CL_ASSERT( p_dm_mad );\r
1571         UNUSED_PARAM( p_iou );\r
1572 \r
1573         p_class_port_info = (ib_class_port_info_t*)&p_dm_mad->data;\r
1574 \r
1575         p_class_port_info->base_ver      = 1;\r
1576         p_class_port_info->class_ver = 1;\r
1577         p_class_port_info->resp_time_val = CL_HTON32( DM_CLASS_RESP_TIME_VALUE );\r
1578 }\r
1579 \r
1580 \r
1581 \r
1582 void\r
1583 get_io_unit_info(\r
1584         IN                              al_iou_t*                                       p_iou,\r
1585         IN                              ib_dm_mad_t*                            p_dm_mad )\r
1586 {\r
1587         ib_iou_info_t*                  p_iou_info;\r
1588         cl_list_item_t*                 p_ioc_item;\r
1589         ib_ioc_handle_t                 h_ioc;\r
1590         uint8_t                                 slot;\r
1591 \r
1592         CL_ASSERT( p_iou );\r
1593         CL_ASSERT( p_dm_mad );\r
1594 \r
1595         p_iou_info = (ib_iou_info_t*)&p_dm_mad->data;\r
1596 \r
1597         cl_spinlock_acquire( &p_iou->obj.lock );\r
1598 \r
1599         p_iou_info->change_id = p_iou->change_id;\r
1600 \r
1601         /* Mark all slots as non-existant. */\r
1602         SET_NIBBLE( &slot, 0, SLOT_DOES_NOT_EXIST );\r
1603         SET_NIBBLE( &slot, 1, SLOT_DOES_NOT_EXIST );\r
1604         cl_memset( p_iou_info->controller_list, slot, sizeof( p_iou->ioc_list ) );\r
1605 \r
1606         /* Now mark the existing slots. */\r
1607         slot = 1;\r
1608         for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list );\r
1609                  p_ioc_item != cl_qlist_end( &p_iou->ioc_list );\r
1610                  p_ioc_item = cl_qlist_next( p_ioc_item ) )\r
1611         {\r
1612                 h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item );\r
1613 \r
1614                 switch( h_ioc->state )\r
1615                 {\r
1616                 case EMPTY_SLOT:\r
1617                 case SLOT_IN_USE:\r
1618                         SET_NIBBLE( p_iou_info->controller_list, slot, IOC_NOT_INSTALLED );\r
1619                         break;\r
1620 \r
1621                 case IOC_ACTIVE:\r
1622                         SET_NIBBLE( p_iou_info->controller_list, slot, IOC_INSTALLED );\r
1623                         break;\r
1624 \r
1625                 default:\r
1626                         break;\r
1627                 }\r
1628                 slot++;\r
1629         }\r
1630 \r
1631         p_iou_info->max_controllers = slot;\r
1632 \r
1633         cl_spinlock_release( &p_iou->obj.lock );\r
1634 }\r
1635 \r
1636 \r
1637 \r
1638 void\r
1639 get_ioc_profile(\r
1640         IN                              al_iou_t*                                       p_iou,\r
1641         IN                              uint8_t                                         slot,\r
1642         IN                              ib_dm_mad_t*                            p_dm_mad )\r
1643 {\r
1644         ib_ioc_profile_t*               p_ioc_profile;\r
1645         cl_list_item_t*                 p_ioc_item;\r
1646         ib_ioc_handle_t                 h_ioc;\r
1647 \r
1648         CL_ASSERT( p_iou );\r
1649         CL_ASSERT( p_dm_mad );\r
1650 \r
1651         p_ioc_profile = (ib_ioc_profile_t*)&p_dm_mad->data;\r
1652 \r
1653         cl_spinlock_acquire( &p_iou->obj.lock );\r
1654 \r
1655         /* Verify that the slot number is within range. */\r
1656         if( ( slot == 0 ) ||\r
1657                 ( slot > cl_qlist_count( &p_iou->ioc_list ) ) )\r
1658         {\r
1659                 cl_spinlock_release( &p_iou->obj.lock );\r
1660                 p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD;\r
1661                 return;\r
1662         }\r
1663 \r
1664         /* The remaining code assumes the slot number starts at zero. */\r
1665         for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list );\r
1666                  p_ioc_item != cl_qlist_end( &p_iou->ioc_list ) && slot;\r
1667                  p_ioc_item = cl_qlist_next( p_ioc_item ) )\r
1668         {\r
1669                 slot--;\r
1670         }\r
1671 \r
1672         h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item );\r
1673 \r
1674         cl_spinlock_acquire( &h_ioc->obj.lock );\r
1675 \r
1676         /* Verify the IOC state. */\r
1677         if( h_ioc->state != IOC_ACTIVE )\r
1678         {\r
1679                 cl_spinlock_release( &h_ioc->obj.lock );\r
1680                 cl_spinlock_release( &p_iou->obj.lock );\r
1681                 p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_IOC_RESP;\r
1682                 return;\r
1683         }\r
1684 \r
1685         /* Copy the IOC profile. */\r
1686         *p_ioc_profile = h_ioc->ioc_profile;\r
1687 \r
1688         cl_spinlock_release( &h_ioc->obj.lock );\r
1689         cl_spinlock_release( &p_iou->obj.lock );\r
1690 }\r
1691 \r
1692 \r
1693 \r
1694 void\r
1695 get_svc_entries(\r
1696         IN                              al_iou_t*                                       p_iou,\r
1697         IN                              uint8_t                                         slot,\r
1698         IN                              uint8_t                                         svc_num_lo,\r
1699         IN                              uint8_t                                         svc_num_hi,\r
1700         IN                              ib_dm_mad_t*                            p_dm_mad )\r
1701 {\r
1702         ib_svc_entries_t*               p_svc_entries;\r
1703         cl_list_item_t*                 p_ioc_item;\r
1704         cl_list_item_t*                 p_list_item;\r
1705         ib_ioc_handle_t                 h_ioc;\r
1706         al_obj_t*                               p_obj;\r
1707         al_svc_entry_t*                 p_svc_entry;\r
1708         uint8_t                                 i, j, k;\r
1709 \r
1710         CL_ASSERT( p_iou );\r
1711         CL_ASSERT( p_dm_mad );\r
1712 \r
1713         p_svc_entries = (ib_svc_entries_t*)&p_dm_mad->data;\r
1714 \r
1715         cl_spinlock_acquire( &p_iou->obj.lock );\r
1716 \r
1717         /*\r
1718          * Verify that the slot number is within range and\r
1719          * a maximum of SVC_ENTRY_COUNT entries is requested.\r
1720          */\r
1721         if( ( slot == 0 ) ||\r
1722                 ( slot > cl_qlist_count( &p_iou->ioc_list ) ) ||\r
1723                 ( ( svc_num_hi - svc_num_lo + 1) > SVC_ENTRY_COUNT ) )\r
1724         {\r
1725                 cl_spinlock_release( &p_iou->obj.lock );\r
1726                 p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD;\r
1727                 return;\r
1728         }\r
1729 \r
1730         /* The remaining code assumes the slot number starts at zero. */\r
1731         for( p_ioc_item = cl_qlist_head( &p_iou->ioc_list );\r
1732                  p_ioc_item != cl_qlist_end( &p_iou->ioc_list ) && slot;\r
1733                  p_ioc_item = cl_qlist_next( p_ioc_item ) )\r
1734         {\r
1735                 slot--;\r
1736         }\r
1737 \r
1738         h_ioc = PARENT_STRUCT( p_ioc_item, al_ioc_t, iou_item );\r
1739 \r
1740         cl_spinlock_acquire( &h_ioc->obj.lock );\r
1741 \r
1742         /* Verify the IOC state. */\r
1743         if( h_ioc->state != IOC_ACTIVE )\r
1744         {\r
1745                 cl_spinlock_release( &h_ioc->obj.lock );\r
1746                 cl_spinlock_release( &p_iou->obj.lock );\r
1747                 p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_IOC_RESP;\r
1748                 return;\r
1749         }\r
1750 \r
1751         /* Verify the service entry range. */\r
1752         if( ( svc_num_lo > h_ioc->ioc_profile.num_svc_entries ) ||\r
1753                 ( svc_num_hi >= h_ioc->ioc_profile.num_svc_entries ) )\r
1754         {\r
1755                 cl_spinlock_release( &h_ioc->obj.lock );\r
1756                 cl_spinlock_release( &p_iou->obj.lock );\r
1757                 p_dm_mad->hdr.status = IB_MAD_STATUS_INVALID_FIELD;\r
1758                 return;\r
1759         }\r
1760 \r
1761         for( i = svc_num_lo, j = 0; j < ( svc_num_hi - svc_num_lo + 1 ); i++, j++ )\r
1762         {\r
1763                 k = i;\r
1764 \r
1765                 /* Locate the service entry. Traverse until k=0. */\r
1766                 for( p_list_item = cl_qlist_head( &h_ioc->obj.obj_list );\r
1767                          k && ( p_list_item != cl_qlist_end( &h_ioc->obj.obj_list ) );\r
1768                          p_list_item = cl_qlist_next( p_list_item ) )\r
1769                 {\r
1770                         k--;\r
1771                 }\r
1772 \r
1773                 if( p_list_item == cl_qlist_end( &h_ioc->obj.obj_list ) )\r
1774                 {\r
1775                         /* The service entry list was empty or the end was reached. */\r
1776                         cl_spinlock_release( &h_ioc->obj.lock );\r
1777                         cl_spinlock_release( &p_iou->obj.lock );\r
1778                         p_dm_mad->hdr.status = IB_DM_MAD_STATUS_NO_SVC_ENTRIES;\r
1779                         return;\r
1780                 }\r
1781 \r
1782                 p_obj = PARENT_STRUCT( p_list_item, al_obj_t, obj_list );\r
1783                 p_svc_entry = PARENT_STRUCT( p_obj, al_svc_entry_t, obj );\r
1784 \r
1785                 /* Copy the service entry. */\r
1786                 p_svc_entries->service_entry[ j ] = p_svc_entry->svc_entry;\r
1787         }\r
1788 \r
1789         cl_spinlock_release( &h_ioc->obj.lock );\r
1790         cl_spinlock_release( &p_iou->obj.lock );\r
1791 }\r