ba8949dae716eb9b35b8c8734e6570c6a98a8e82
[mirror/winof/.git] / ulp / srp / kernel / srp_hba.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  *\r
29  * $Id$\r
30  */\r
31 \r
32 \r
33 \r
34 \r
35 #include "srp_hba.h"\r
36 #include "srp_data.h"\r
37 #include "srp_data_path.h"\r
38 #include "srp_debug.h"\r
39 #include "srp_session.h"\r
40 \r
41 #include <complib/cl_byteswap.h>\r
42 #include <complib/cl_bus_ifc.h>\r
43 #include <initguid.h>\r
44 #include <iba/ioc_ifc.h>\r
45 \r
46 \r
47 static void\r
48 __srp_destroying_hba(\r
49         IN                              cl_obj_t                                        *p_obj );\r
50 \r
51 static void\r
52 __srp_cleanup_hba(\r
53         IN                              cl_obj_t                                        *p_obj );\r
54 \r
55 static void\r
56 __srp_free_hba(\r
57         IN                              cl_obj_t                                        *p_obj );\r
58 \r
59 static ib_api_status_t\r
60 __srp_pnp_cb(\r
61         IN                              ib_pnp_rec_t                            *p_pnp_rec );\r
62 \r
63 void\r
64 __srp_dump_ioc_info( const ib_ioc_info_t *p_ioc_info )\r
65 {\r
66         UNUSED_PARAM( p_ioc_info );\r
67 \r
68         SRP_PRINT( SRP_DBG_VERBOSE, ("Dumping IOC Info\n") );\r
69 \r
70         SRP_PRINT( SRP_DBG_VERBOSE, ("   chassis_guid    = 0x%"PRIx64"\n", cl_ntoh64( p_ioc_info->chassis_guid )) );\r
71         SRP_PRINT( SRP_DBG_VERBOSE, ("   chassis_slot    = %d\n",          p_ioc_info->chassis_slot) );\r
72         SRP_PRINT( SRP_DBG_VERBOSE, ("   iou_guid        = 0x%"PRIx64"\n", cl_ntoh64( p_ioc_info->iou_guid )) );\r
73         SRP_PRINT( SRP_DBG_VERBOSE, ("   iou_slot        = %d\n",          p_ioc_info->iou_slot) );\r
74         SRP_PRINT( SRP_DBG_VERBOSE, ("\n") );\r
75         SRP_PRINT( SRP_DBG_VERBOSE, ("Dumping IOC Info Profile\n") );\r
76 \r
77         SRP_PRINT( SRP_DBG_VERBOSE, ("   ioc_guid        = 0x%"PRIx64"\n", cl_ntoh64( p_ioc_info->profile.ioc_guid )) );\r
78         SRP_PRINT( SRP_DBG_VERBOSE, ("   vend_id         = %d\n",          cl_ntoh32( p_ioc_info->profile.vend_id )) );\r
79         SRP_PRINT( SRP_DBG_VERBOSE, ("   dev_id          = %d\n",          cl_ntoh32( p_ioc_info->profile.dev_id )) );\r
80         SRP_PRINT( SRP_DBG_VERBOSE, ("   dev_ver         = %d\n",          cl_ntoh16( p_ioc_info->profile.dev_ver )) );\r
81 \r
82         SRP_PRINT( SRP_DBG_VERBOSE, ("   subsys_vend_id  = %d\n",          cl_ntoh32( p_ioc_info->profile.subsys_vend_id )) );\r
83         SRP_PRINT( SRP_DBG_VERBOSE, ("   subsys_id       = %d\n",          cl_ntoh32( p_ioc_info->profile.subsys_id )) );\r
84 \r
85         SRP_PRINT( SRP_DBG_VERBOSE, ("   io_class        = %d\n",          cl_ntoh16( p_ioc_info->profile.io_class )) );\r
86         SRP_PRINT( SRP_DBG_VERBOSE, ("   io_subclass     = %d\n",          cl_ntoh16( p_ioc_info->profile.io_subclass )) );\r
87         SRP_PRINT( SRP_DBG_VERBOSE, ("   protocol        = %d\n",          cl_ntoh16( p_ioc_info->profile.protocol )) );\r
88         SRP_PRINT( SRP_DBG_VERBOSE, ("   protocol_ver    = %d\n",          cl_ntoh16( p_ioc_info->profile.protocol_ver )) );\r
89 \r
90         SRP_PRINT( SRP_DBG_VERBOSE, ("   send_msg_depth  = %d\n",          cl_ntoh16( p_ioc_info->profile.send_msg_depth )) );\r
91         SRP_PRINT( SRP_DBG_VERBOSE, ("   rdma_read_depth = %d\n",          p_ioc_info->profile.rdma_read_depth) );\r
92         SRP_PRINT( SRP_DBG_VERBOSE, ("   send_msg_size   = %d\n",          cl_ntoh32( p_ioc_info->profile.send_msg_size )) );\r
93         SRP_PRINT( SRP_DBG_VERBOSE, ("   rdma_size       = %d\n",          cl_ntoh32( p_ioc_info->profile.rdma_size )) );\r
94 \r
95         SRP_PRINT( SRP_DBG_VERBOSE, ("   ctrl_ops_cap    = 0x%X\n",        p_ioc_info->profile.ctrl_ops_cap) );\r
96         SRP_PRINT( SRP_DBG_VERBOSE, ("   num_svc_entries = 0x%X\n",        p_ioc_info->profile.num_svc_entries) );\r
97         SRP_PRINT( SRP_DBG_VERBOSE, ("   id_string       = %s\n",          p_ioc_info->profile.id_string) );\r
98 }\r
99 \r
100 \r
101 static boolean_t\r
102 __get_ioc_ifc(\r
103         IN                              srp_hba_t* const                        p_hba )\r
104 {\r
105         NTSTATUS                        status;\r
106         ib_al_ifc_data_t        data;\r
107         IO_STACK_LOCATION       io_stack;\r
108 \r
109         SRP_ENTER( SRP_DBG_PNP );\r
110 \r
111         /* Query for our interface. */\r
112         data.size = sizeof(ioc_ifc_data_t);\r
113         data.version = IOC_INTERFACE_DATA_VERSION;\r
114         data.type = &GUID_IOC_INTERFACE_DATA;\r
115         data.p_data = &p_hba->info;\r
116 \r
117         io_stack.MinorFunction = IRP_MN_QUERY_INTERFACE;\r
118         io_stack.Parameters.QueryInterface.Version = AL_INTERFACE_VERSION;\r
119         io_stack.Parameters.QueryInterface.Size = sizeof(ib_al_ifc_t);\r
120         io_stack.Parameters.QueryInterface.Interface = (INTERFACE*)&p_hba->ifc;\r
121         io_stack.Parameters.QueryInterface.InterfaceSpecificData = &data;\r
122         io_stack.Parameters.QueryInterface.InterfaceType = &GUID_IB_AL_INTERFACE;\r
123 \r
124         status = cl_fwd_query_ifc( gp_self_do, &io_stack );\r
125         if( !NT_SUCCESS( status ) )\r
126         {\r
127                 SRP_TRACE_EXIT( SRP_DBG_ERROR,\r
128                         ("Query interface for IOU parameters returned %08x.\n", status) );\r
129                 return FALSE;\r
130         }\r
131         else\r
132         {\r
133                 /*\r
134                  * Dereference the interface now so that the bus driver doesn't fail a\r
135                  * query remove IRP.  We will always get unloaded before the bus driver\r
136                  * since we're a child device.\r
137                  */\r
138                 p_hba->ifc.wdm.InterfaceDereference( p_hba->ifc.wdm.Context );\r
139                 SRP_EXIT( SRP_DBG_PNP );\r
140                 return TRUE;\r
141         }\r
142 }\r
143 \r
144 \r
145 ib_api_status_t\r
146 srp_hba_create(\r
147         IN                              cl_obj_t* const                         p_drv_obj,\r
148                 OUT                     srp_ext_t* const                        p_ext )\r
149 {\r
150         srp_hba_t                       *p_hba;\r
151         cl_status_t                     cl_status;\r
152         ib_api_status_t         ib_status;\r
153         ib_pnp_req_t            pnp_req;\r
154         uint32_t                        i;\r
155 \r
156         SRP_ENTER( SRP_DBG_PNP );\r
157 \r
158         p_hba = (srp_hba_t*)cl_zalloc( sizeof(srp_hba_t) );\r
159         if( !p_hba )\r
160         {\r
161                 SRP_TRACE_EXIT( SRP_DBG_ERROR,\r
162                         ("Failed to allocate srp_hba_t structure.\n") );\r
163                 return IB_INSUFFICIENT_MEMORY;\r
164         }\r
165 \r
166         cl_qlist_init( &p_hba->path_record_list );\r
167         cl_spinlock_init( &p_hba->path_record_list_lock );\r
168 \r
169         /* Store instance parameters. */\r
170         p_hba->p_ext = p_ext;\r
171         p_hba->max_sg = 0xFFFFFFFF;\r
172         p_hba->max_srb_ext_sz = 0xFFFFFFFF;\r
173 \r
174         if( !__get_ioc_ifc( p_hba ) )\r
175         {\r
176                 SRP_TRACE_EXIT( SRP_DBG_ERROR, ("__get_ioc_ifc failed.\n") );\r
177                 return IB_ERROR;\r
178         }\r
179 \r
180         for ( i = 0; i < SRP_MAX_SERVICE_ENTRIES; i++ )\r
181         {\r
182                 p_hba->session_list[i] = NULL;\r
183         }\r
184 \r
185         cl_obj_construct( &p_hba->obj, SRP_OBJ_TYPE_HBA );\r
186         cl_status = cl_obj_init( &p_hba->obj, CL_DESTROY_ASYNC,\r
187                 __srp_destroying_hba, __srp_cleanup_hba, __srp_free_hba );\r
188         if( cl_status != CL_SUCCESS )\r
189         {\r
190                 SRP_TRACE_EXIT( SRP_DBG_ERROR,\r
191                         ("cl_obj_init returned %s\n", cl_status_text[cl_status]) );\r
192                 return IB_ERROR;\r
193         }\r
194 \r
195         ib_status = p_hba->ifc.open_al( &p_hba->h_al );\r
196         if( ib_status != IB_SUCCESS )\r
197         {\r
198                 SRP_TRACE( SRP_DBG_VERBOSE, ("HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) );\r
199                 cl_obj_destroy( &p_hba->obj );\r
200                 SRP_TRACE_EXIT( SRP_DBG_ERROR,\r
201                         ("ib_open_al returned %s\n", p_hba->ifc.get_err_str( ib_status )) );\r
202                 return ib_status;\r
203         }\r
204 \r
205         /* Register for IOC events */\r
206         pnp_req.pfn_pnp_cb = __srp_pnp_cb;\r
207         pnp_req.pnp_class = IB_PNP_IOC | IB_PNP_FLAG_REG_SYNC;\r
208         pnp_req.pnp_context = p_hba;\r
209         /* Reference the HBA object before registering for PnP notifications. */\r
210         cl_obj_ref( &p_hba->obj );\r
211 \r
212         cl_obj_insert_rel( &p_hba->rel, p_drv_obj, &p_hba->obj );\r
213 \r
214         ib_status = p_hba->ifc.reg_pnp( p_hba->h_al, &pnp_req, &p_hba->h_pnp );\r
215         if( ib_status != IB_SUCCESS )\r
216         {\r
217                 SRP_TRACE( SRP_DBG_VERBOSE, ("HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) );\r
218                 cl_obj_destroy( &p_hba->obj );\r
219                 SRP_TRACE_EXIT( SRP_DBG_ERROR,\r
220                         ("ib_reg_pnp returned %s\n", p_hba->ifc.get_err_str( ib_status )) );\r
221                 return ib_status;\r
222         }\r
223 \r
224         /*\r
225          * Add the HBA to the driver object's child list.  This will cause\r
226          * everything to clean up properly in case we miss an unload notification.\r
227          */\r
228         p_ext->p_hba = p_hba;\r
229 \r
230         if ( p_hba->session_list[0] == NULL )\r
231         {\r
232                 p_ext->p_hba = NULL;\r
233                 SRP_TRACE( SRP_DBG_VERBOSE, ("HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) );\r
234                 cl_obj_destroy( &p_hba->obj );\r
235 \r
236                 SRP_TRACE( SRP_DBG_ERROR, ("Session Connection Failure.\n") );\r
237                 ib_status = IB_ERROR;\r
238         }\r
239 \r
240         SRP_EXIT( SRP_DBG_PNP );\r
241         return ib_status;\r
242 }\r
243 \r
244 \r
245 static void\r
246 __srp_destroying_hba(\r
247         IN              cl_obj_t                    *p_obj )\r
248 {\r
249         srp_hba_t       *p_hba;\r
250 \r
251         SRP_ENTER( SRP_DBG_PNP );\r
252 \r
253         p_hba = PARENT_STRUCT( p_obj, srp_hba_t, obj );\r
254 \r
255         SRP_TRACE( SRP_DBG_VERBOSE, ("Before dereg pnp HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) );\r
256 \r
257         if( p_hba->h_pnp )\r
258         {\r
259                 p_hba->ifc.dereg_pnp( p_hba->h_pnp, cl_obj_deref );\r
260         }\r
261 \r
262         SRP_TRACE( SRP_DBG_VERBOSE, ("After dereg pnp HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) );\r
263 \r
264         SRP_EXIT( SRP_DBG_PNP );\r
265 }\r
266 \r
267 static void\r
268 __srp_remove_path_records(\r
269         IN              srp_hba_t                   *p_hba )\r
270 {\r
271         srp_path_record_t   *p_srp_path_record;\r
272 \r
273         SRP_ENTER( SRP_DBG_PNP );\r
274 \r
275         cl_spinlock_acquire( &p_hba->path_record_list_lock );\r
276         p_srp_path_record = (srp_path_record_t *)cl_qlist_remove_head( &p_hba->path_record_list );\r
277 \r
278         SRP_TRACE( SRP_DBG_DEBUG, ("Removing any remaining path records.\n") );\r
279 \r
280         while ( p_srp_path_record != (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) )\r
281         {\r
282                 cl_free( p_srp_path_record );\r
283                 p_srp_path_record = (srp_path_record_t *)cl_qlist_remove_head( &p_hba->path_record_list );\r
284         }\r
285 \r
286         cl_spinlock_release( &p_hba->path_record_list_lock );\r
287 \r
288         SRP_EXIT( SRP_DBG_PNP );\r
289 }\r
290 \r
291 static void\r
292 __srp_cleanup_hba(\r
293         IN              cl_obj_t                    *p_obj )\r
294 {\r
295         srp_hba_t   *p_hba;\r
296 \r
297         SRP_ENTER( SRP_DBG_PNP );\r
298 \r
299         p_hba = PARENT_STRUCT( p_obj, srp_hba_t, obj );\r
300 \r
301         if( p_hba->h_al )\r
302                 p_hba->ifc.close_al( p_hba->h_al );\r
303 \r
304         __srp_remove_path_records( p_hba );\r
305 \r
306         cl_spinlock_destroy( &p_hba->path_record_list_lock );\r
307 \r
308         if ( p_hba->p_svc_entries )\r
309                 cl_free( p_hba->p_svc_entries );\r
310 \r
311         SRP_EXIT( SRP_DBG_PNP );\r
312 }\r
313 \r
314 \r
315 static void\r
316 __srp_free_hba(\r
317         IN              cl_obj_t                    *p_obj )\r
318 {\r
319         srp_hba_t       *p_hba;\r
320 \r
321         SRP_ENTER( SRP_DBG_PNP );\r
322 \r
323         p_hba = PARENT_STRUCT( p_obj, srp_hba_t, obj );\r
324 \r
325         cl_obj_deinit( p_obj );\r
326         cl_free( p_hba );\r
327 \r
328         SRP_EXIT( SRP_DBG_PNP );\r
329 }\r
330 \r
331 static BOOLEAN\r
332 __srp_validate_ioc(\r
333         IN  ib_pnp_ioc_rec_t    *p_ioc_rec )\r
334 {\r
335         SRP_ENTER( SRP_DBG_PNP );\r
336 \r
337         // Is this really an SRP device?\r
338         if ( ( cl_ntoh16( p_ioc_rec->info.profile.io_class )  != SRP_IO_CLASS &&\r
339                    cl_ntoh16( p_ioc_rec->info.profile.io_class )  != SRP_IO_CLASS_R10 ) ||\r
340                  cl_ntoh16( p_ioc_rec->info.profile.io_subclass ) != SRP_IO_SUBCLASS )\r
341         {\r
342                 SRP_TRACE_EXIT( SRP_DBG_ERROR, ("Not an SRP CLASS(0x%x)/SUBCLASS(0x%x).\n",\r
343                                                 cl_ntoh16( p_ioc_rec->info.profile.io_class ),\r
344                                                 cl_ntoh16( p_ioc_rec->info.profile.io_subclass )) );\r
345                 return FALSE;\r
346         }\r
347 \r
348         // Does it have the required features?\r
349         if ( cl_ntoh16( p_ioc_rec->info.profile.protocol )     != SRP_PROTOCOL     ||\r
350                  cl_ntoh16( p_ioc_rec->info.profile.protocol_ver ) != SRP_PROTOCOL_VER ||\r
351                  !(p_ioc_rec->info.profile.ctrl_ops_cap & CTRL_OPS_CAP_ST) ||\r
352                  !(p_ioc_rec->info.profile.ctrl_ops_cap & CTRL_OPS_CAP_SF) ||\r
353                  !(p_ioc_rec->info.profile.ctrl_ops_cap & CTRL_OPS_CAP_RF) ||\r
354                  !(p_ioc_rec->info.profile.ctrl_ops_cap & CTRL_OPS_CAP_WF) )\r
355         {\r
356                 SRP_TRACE_EXIT( SRP_DBG_ERROR, ("Not an SRP PROTOCOL/PROTOCOL_VER.\n") );\r
357                 return FALSE;\r
358         }\r
359 \r
360         // Can it handle our IO requirements?\r
361         if ( cl_ntoh32( p_ioc_rec->info.profile.send_msg_size )  <  SRP_MIN_TGT_TO_INI_IU ||\r
362                  cl_ntoh16( p_ioc_rec->info.profile.send_msg_depth ) == 0 ||\r
363                  cl_ntoh32( p_ioc_rec->info.profile.rdma_size )      <  SRP_MIN_TGT_TO_INI_DMA )\r
364         {\r
365                 SRP_TRACE_EXIT( SRP_DBG_ERROR, ("Device Not Capable.\n") );\r
366                 return FALSE;\r
367         }\r
368 \r
369         SRP_EXIT( SRP_DBG_PNP );\r
370 \r
371         return TRUE;\r
372 }\r
373 \r
374 static BOOLEAN\r
375 __srp_path_rec_equal(\r
376         IN      const ib_path_rec_t     *p_path_rec_1,\r
377         IN      const ib_path_rec_t     *p_path_rec_2,\r
378         IN      BOOLEAN                         check_num_path,\r
379         IN      BOOLEAN                         check_preference )\r
380 {\r
381         SRP_ENTER( SRP_DBG_PNP );\r
382 \r
383         if ( p_path_rec_1->dgid.unicast.prefix != p_path_rec_2->dgid.unicast.prefix )\r
384                 return ( FALSE );\r
385 \r
386         if ( p_path_rec_1->dgid.unicast.interface_id != p_path_rec_2->dgid.unicast.interface_id )\r
387                 return ( FALSE );\r
388 \r
389         if ( p_path_rec_1->sgid.unicast.prefix != p_path_rec_2->sgid.unicast.prefix )\r
390                 return ( FALSE );\r
391 \r
392         if ( p_path_rec_1->sgid.unicast.interface_id != p_path_rec_2->sgid.unicast.interface_id )\r
393                 return ( FALSE );\r
394 \r
395         if ( p_path_rec_1->dlid != p_path_rec_2->dlid )\r
396                 return ( FALSE );\r
397 \r
398         if ( p_path_rec_1->slid != p_path_rec_2->slid )\r
399                 return ( FALSE );\r
400 \r
401         if ( p_path_rec_1->hop_flow_raw.val != p_path_rec_2->hop_flow_raw.val )\r
402         {\r
403                 SRP_TRACE( SRP_DBG_DEBUG, ("hop_flow_raw.val does not match.\n") );\r
404                 return ( FALSE );\r
405         }\r
406 \r
407         if ( p_path_rec_1->tclass != p_path_rec_2->tclass )\r
408         {\r
409                 SRP_TRACE( SRP_DBG_DEBUG, ("tclass does not match.\n") );\r
410                 return ( FALSE );\r
411         }\r
412 \r
413         if ( p_path_rec_1->num_path != p_path_rec_2->num_path )\r
414         {\r
415                 SRP_TRACE( SRP_DBG_DEBUG, ("num_path does not match.\n") );\r
416                 if ( check_num_path == TRUE )\r
417                 {\r
418                         return ( FALSE );\r
419                 }\r
420         }\r
421 \r
422         if ( p_path_rec_1->pkey != p_path_rec_2->pkey )\r
423         {\r
424                 SRP_TRACE( SRP_DBG_DEBUG, ("pkey does not match.\n") );\r
425                 return ( FALSE );\r
426         }\r
427 \r
428         if ( p_path_rec_1->sl != p_path_rec_2->sl )\r
429         {\r
430                 SRP_TRACE( SRP_DBG_DEBUG, ("sl does not match.\n") );\r
431                 return ( FALSE );\r
432         }\r
433 \r
434         if ( p_path_rec_1->mtu != p_path_rec_2->mtu )\r
435         {\r
436                 SRP_TRACE( SRP_DBG_DEBUG, ("mtu does not match.\n") );\r
437                 return ( FALSE );\r
438         }\r
439 \r
440         if ( p_path_rec_1->rate != p_path_rec_2->rate )\r
441         {\r
442                 SRP_TRACE( SRP_DBG_DEBUG, ("rate does not match.\n") );\r
443                 return ( FALSE );\r
444         }\r
445 \r
446         if ( p_path_rec_1->pkt_life != p_path_rec_2->pkt_life )\r
447         {\r
448                 SRP_TRACE( SRP_DBG_DEBUG, ("pkt_life does not match.\n") );\r
449                 return ( FALSE );\r
450         }\r
451 \r
452         if ( p_path_rec_1->preference != p_path_rec_2->preference )\r
453         {\r
454                 SRP_TRACE( SRP_DBG_DEBUG, ("preference does not match.\n") );\r
455                 if ( check_preference == TRUE )\r
456                 {\r
457                         return ( FALSE );\r
458                 }\r
459         }\r
460 \r
461 #if defined( _DEBUG_ )\r
462 \r
463         if ( p_path_rec_1->resv0 != p_path_rec_2->resv0 )\r
464         {\r
465                 SRP_TRACE( SRP_DBG_DEBUG, ("resv0 does not match.\n") );\r
466         }\r
467 \r
468         if ( p_path_rec_1->resv1 != p_path_rec_2->resv1 )\r
469         {\r
470                 SRP_TRACE( SRP_DBG_DEBUG, ("resv1 does not match.\n") );\r
471         }\r
472 \r
473         if ( p_path_rec_1->resv2 != p_path_rec_2->resv2 )\r
474         {\r
475                 SRP_TRACE( SRP_DBG_DEBUG, ("resv2 does not match.\n") );\r
476         }\r
477 \r
478         if ( cl_memcmp( p_path_rec_1, p_path_rec_2, sizeof( ib_path_rec_t ) ) != 0 )\r
479         {\r
480                 SRP_TRACE( SRP_DBG_DEBUG, ("p_path_rec_1 does not match p_path_rec_2.\n") );\r
481         }\r
482         else\r
483         {\r
484                 SRP_TRACE( SRP_DBG_DEBUG, ("p_path_rec_1 matches p_path_rec_2.\n") );\r
485         }\r
486 \r
487 #endif\r
488 \r
489         SRP_EXIT( SRP_DBG_PNP );\r
490 \r
491         return ( TRUE );\r
492 }\r
493 \r
494 static\r
495 srp_path_record_t*\r
496 __srp_find_path(\r
497         IN  srp_hba_t               *p_hba,\r
498         IN  const ib_path_rec_t     *p_path_rec,\r
499         IN  BOOLEAN                 check_num_path,\r
500         IN  BOOLEAN                 check_preference )\r
501 {\r
502         srp_path_record_t   *p_srp_path_record;\r
503 \r
504         SRP_ENTER( SRP_DBG_PNP );\r
505 \r
506         SRP_TRACE( SRP_DBG_VERBOSE,\r
507                 ("Finding path record (slid:%d dlid:%d) for %s.\n",\r
508                 p_path_rec->slid,\r
509                 p_path_rec->dlid,\r
510                 p_hba->ioc_info.profile.id_string) );\r
511 \r
512         cl_spinlock_acquire( &p_hba->path_record_list_lock );\r
513 \r
514         p_srp_path_record = (srp_path_record_t *)cl_qlist_head( &p_hba->path_record_list );\r
515 \r
516         while ( p_srp_path_record != (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) )\r
517         {\r
518                 if ( __srp_path_rec_equal( (const ib_path_rec_t *)&p_srp_path_record->path_rec,\r
519                                                                         p_path_rec,\r
520                                                                         check_num_path,\r
521                                                                         check_preference ) == TRUE )\r
522                 {\r
523                         SRP_TRACE( SRP_DBG_VERBOSE,\r
524                                 ("Found path record (slid:%d dlid:%d) for %s.\n",\r
525                                 p_path_rec->slid,\r
526                                 p_path_rec->dlid,\r
527                                 p_hba->ioc_info.profile.id_string) );\r
528                         break;\r
529                 }\r
530 \r
531                 p_srp_path_record = (srp_path_record_t *)cl_qlist_next( &p_srp_path_record->list_item );\r
532         }\r
533 \r
534         if ( p_srp_path_record == (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) )\r
535         {\r
536                 p_srp_path_record = NULL;\r
537         }\r
538 \r
539         cl_spinlock_release( &p_hba->path_record_list_lock );\r
540 \r
541         SRP_EXIT( SRP_DBG_PNP );\r
542 \r
543         return p_srp_path_record;\r
544 }\r
545 \r
546 static\r
547 srp_path_record_t*\r
548 __srp_remove_path(\r
549         IN  srp_hba_t               *p_hba,\r
550         IN  const ib_path_rec_t     *p_path_rec )\r
551 {\r
552         srp_path_record_t   *p_srp_path_record;\r
553 \r
554         SRP_ENTER( SRP_DBG_PNP );\r
555 \r
556         p_srp_path_record = __srp_find_path( p_hba, p_path_rec, TRUE, TRUE );\r
557         if ( p_srp_path_record != NULL )\r
558         {\r
559                 cl_spinlock_acquire( &p_hba->path_record_list_lock );\r
560 \r
561                 SRP_TRACE( SRP_DBG_VERBOSE,\r
562                         ("Removing path record (slid:%d dlid:%d) for %s.\n",\r
563                         p_path_rec->slid,\r
564                         p_path_rec->dlid,\r
565                         p_hba->ioc_info.profile.id_string) );\r
566 \r
567                 cl_qlist_remove_item( &p_hba->path_record_list, &p_srp_path_record->list_item );\r
568 \r
569                 cl_spinlock_release( &p_hba->path_record_list_lock );\r
570         }\r
571 \r
572         SRP_TRACE( SRP_DBG_DEBUG,\r
573                 ("Current Path count for %s = %d \n",\r
574                  p_hba->ioc_info.profile.id_string,\r
575                  cl_qlist_count( &p_hba->path_record_list )) );\r
576 \r
577         SRP_EXIT( SRP_DBG_PNP );\r
578 \r
579         return p_srp_path_record;\r
580 }\r
581 \r
582 static\r
583 srp_path_record_t*\r
584 __srp_add_path(\r
585         IN  srp_hba_t               *p_hba,\r
586         IN  const ib_path_rec_t     *p_path_rec )\r
587 {\r
588         srp_path_record_t   *p_srp_path_record;\r
589 \r
590         SRP_ENTER( SRP_DBG_PNP );\r
591 \r
592         p_srp_path_record = __srp_find_path( p_hba, p_path_rec, FALSE, FALSE );\r
593         if ( p_srp_path_record != NULL )\r
594         {\r
595                 cl_spinlock_acquire( &p_hba->path_record_list_lock );\r
596                 p_srp_path_record->path_rec = *p_path_rec;\r
597                 cl_spinlock_release( &p_hba->path_record_list_lock );\r
598 \r
599                 SRP_TRACE( SRP_DBG_WARN,\r
600                         ("Discarding/Updating duplicate path record (slid:%d dlid:%d) for %s.\n",\r
601                         p_path_rec->slid,\r
602                         p_path_rec->dlid,\r
603                         p_hba->ioc_info.profile.id_string) );\r
604 \r
605                 goto exit;\r
606         }\r
607 \r
608         SRP_TRACE( SRP_DBG_VERBOSE,\r
609                 ("Adding path record (slid:%d dlid:%d) for %s.\n",\r
610                 p_path_rec->slid,\r
611                 p_path_rec->dlid,\r
612                 p_hba->ioc_info.profile.id_string) );\r
613 \r
614 \r
615         p_srp_path_record = cl_zalloc( sizeof( srp_path_record_t ) );\r
616         if ( p_srp_path_record == NULL )\r
617         {\r
618                 SRP_TRACE( SRP_DBG_ERROR, ("Insufficient Memory.\n") );\r
619         }\r
620         else\r
621         {\r
622                 p_srp_path_record->path_rec = *p_path_rec;\r
623 \r
624                 cl_spinlock_acquire( &p_hba->path_record_list_lock );\r
625                 cl_qlist_insert_tail( &p_hba->path_record_list, &p_srp_path_record->list_item );\r
626                 cl_spinlock_release( &p_hba->path_record_list_lock );\r
627         }\r
628 \r
629         SRP_TRACE( SRP_DBG_DEBUG,\r
630                 ("Current Path count for %s = %d \n",\r
631                  p_hba->ioc_info.profile.id_string,\r
632                  cl_qlist_count( &p_hba->path_record_list )) );\r
633 \r
634 exit:\r
635         SRP_EXIT( SRP_DBG_PNP );\r
636 \r
637         return p_srp_path_record;\r
638 }\r
639 \r
640 static ib_api_status_t\r
641 __srp_connect_sessions(\r
642         IN OUT srp_hba_t    *p_hba )\r
643 {\r
644         uint32_t        i;\r
645         srp_session_t   *p_session;\r
646         ib_api_status_t status = IB_ERROR;\r
647 \r
648         SRP_ENTER( SRP_DBG_PNP );\r
649 \r
650         /* Create the session(s). */\r
651         for ( i = 0; i < p_hba->ioc_info.profile.num_svc_entries; i++ )\r
652         {\r
653                 BOOLEAN any_ioc_connected = FALSE;\r
654                 int     retry_count = 0;\r
655 \r
656                 do\r
657                 {\r
658                         retry_count++;\r
659 \r
660                         SRP_TRACE( SRP_DBG_DEBUG,\r
661                                 ("Attempting to connect %s. Connection Attempt Count = %d.\n",\r
662                                  p_hba->ioc_info.profile.id_string,\r
663                                  retry_count) );\r
664 \r
665                         SRP_TRACE( SRP_DBG_VERBOSE,\r
666                                 ("Creating New Session For Service Entry Index %d.\n", p_hba->ioc_info.profile.num_svc_entries));\r
667                         p_session = srp_new_session( p_hba,\r
668                                                                                  p_hba->ioc_info.profile.ioc_guid,\r
669                                                                                  &p_hba->p_svc_entries[i],\r
670                                                                                  &status );\r
671                         if ( p_session == NULL )\r
672                         {\r
673                                 status = IB_INSUFFICIENT_MEMORY;\r
674                                 break;\r
675                         }\r
676 \r
677                         SRP_TRACE( SRP_DBG_VERBOSE,\r
678                                 ("New Session For Service Entry Index %d Created.\n", p_hba->ioc_info.profile.num_svc_entries));\r
679                         SRP_TRACE( SRP_DBG_VERBOSE,\r
680                                 ("Logging Into Session.\n"));\r
681                         status = srp_session_login( p_session );\r
682                         if ( status == IB_SUCCESS )\r
683                         {\r
684                                 any_ioc_connected = TRUE;\r
685 \r
686                                 if ( (p_hba->max_sg >\r
687                                         p_session->connection.max_scatter_gather_entries)\r
688                                         && !(p_session->connection.descriptor_format &\r
689                                         DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS) )\r
690                                 {\r
691                                         p_hba->max_sg = p_session->connection.max_scatter_gather_entries;\r
692                                 }\r
693 \r
694                                 if ( p_hba->max_srb_ext_sz > p_session->connection.init_to_targ_iu_sz )\r
695                                 {\r
696                                         p_hba->max_srb_ext_sz =\r
697                                                 sizeof( srp_send_descriptor_t ) -\r
698                                                 SRP_MIN_IU_SIZE +\r
699                                                 p_session->connection.init_to_targ_iu_sz;\r
700                                 }\r
701 \r
702                                 cl_obj_lock( &p_hba->obj );\r
703                                 p_hba->session_list[i] = p_session;\r
704                                 cl_obj_unlock( &p_hba->obj );\r
705 \r
706                                 SRP_TRACE( SRP_DBG_VERBOSE,\r
707                                         ("Session Login Issued Successfully.\n"));\r
708                         }\r
709                         else\r
710                         {\r
711                                 SRP_TRACE( SRP_DBG_ERROR,\r
712                                         ("Session Login Failure Status = %d.\n", status));\r
713                                 SRP_TRACE( SRP_DBG_VERBOSE, ("Session Object ref_cnt = %d\n", p_session->obj.ref_cnt) );\r
714                                 cl_obj_destroy( &p_session->obj );\r
715                         }\r
716                 } while ( (status != IB_SUCCESS) && (retry_count < 3) );\r
717 \r
718                 if ( any_ioc_connected == TRUE )\r
719                 {\r
720                         status = IB_SUCCESS;\r
721                         if ( p_hba->adapter_paused == TRUE )\r
722                         {\r
723                                 SRP_TRACE( SRP_DBG_DEBUG, ("Resuming Adapter for %s.\n", p_hba->ioc_info.profile.id_string) );\r
724                                 p_hba->adapter_paused = FALSE;\r
725                                 StorPortReady( p_hba->p_ext );\r
726 //                              StorPortNotification( BusChangeDetected, p_hba->p_ext, 0 );\r
727                         }\r
728                 }\r
729         }\r
730 \r
731         SRP_EXIT( SRP_DBG_PNP );\r
732 \r
733         return status;\r
734 }\r
735 \r
736 static void\r
737 __srp_disconnect_sessions(\r
738         IN                              srp_hba_t                                       *p_hba,\r
739         IN                              BOOLEAN                                         pause_adapter )\r
740 {\r
741         uint32_t                i;\r
742         srp_session_t   *p_session;\r
743 \r
744         SRP_ENTER( SRP_DBG_PNP );\r
745 \r
746         cl_obj_lock( &p_hba->obj );\r
747 \r
748         for ( i = 0; i < p_hba->ioc_info.profile.num_svc_entries; i++ )\r
749         {\r
750                 if ( p_hba->session_list[i] != NULL )\r
751                 {\r
752                         break;\r
753                 }\r
754         }\r
755 \r
756         cl_obj_unlock( &p_hba->obj );\r
757 \r
758         if ( i == p_hba->ioc_info.profile.num_svc_entries )\r
759         {\r
760                 SRP_TRACE( SRP_DBG_DEBUG, ("No current connections to %s.\n", p_hba->ioc_info.profile.id_string) );\r
761                 goto exit;\r
762         }\r
763 \r
764         SRP_TRACE( SRP_DBG_DEBUG, ("Current path to %s has been lost.\n", p_hba->ioc_info.profile.id_string) );\r
765 \r
766         p_hba->p_srp_path_record = NULL;\r
767 \r
768         if ( pause_adapter == TRUE )\r
769         {\r
770                 if ( p_hba->adapter_paused == FALSE )\r
771                 {\r
772                         p_hba->adapter_paused = TRUE;\r
773                         StorPortBusy( p_hba->p_ext, (ULONG)-1 );\r
774                         StorPortCompleteRequest( p_hba->p_ext,\r
775                                                                          SP_UNTAGGED,\r
776                                                                          SP_UNTAGGED,\r
777                                                                          SP_UNTAGGED,\r
778                                                                          SRB_STATUS_BUSY );\r
779                         SRP_TRACE( SRP_DBG_DEBUG, ("Pausing Adapter for %s.\n", p_hba->ioc_info.profile.id_string) );\r
780                 }\r
781         }\r
782 \r
783         /* Destroy all the connections. */\r
784         SRP_TRACE( SRP_DBG_DEBUG, ("Destroy all connections to %s.\n", p_hba->ioc_info.profile.id_string) );\r
785 \r
786         for ( i = 0; i < p_hba->ioc_info.profile.num_svc_entries; i++ )\r
787         {\r
788                 cl_obj_lock( &p_hba->obj );\r
789                 p_session = p_hba->session_list[i];\r
790                 p_hba->session_list[i] = NULL;\r
791                 cl_obj_unlock( &p_hba->obj );\r
792 \r
793                 if ( p_session != NULL )\r
794                 {\r
795                         SRP_TRACE( SRP_DBG_VERBOSE, ("Session Object ref_cnt = %d\n", p_session->obj.ref_cnt) );\r
796                         __srp_cleanup_session ( &p_session->obj );\r
797                         cl_obj_destroy( &p_session->obj );\r
798                 }\r
799                 else\r
800                 {\r
801                         SRP_TRACE( SRP_DBG_WARN,\r
802                                 ("Session for Target ID %d on %s is NULL.\n",\r
803                                  i,\r
804                                  p_hba->ioc_info.profile.id_string) ); // <-- OK in a shutdown or target disconnect\r
805                 }\r
806         }\r
807 \r
808 exit:\r
809         SRP_EXIT( SRP_DBG_PNP );\r
810 }\r
811 \r
812 static ib_api_status_t\r
813 __srp_connect_path(\r
814         IN  srp_hba_t   *p_hba )\r
815 {\r
816         ib_api_status_t     status = IB_ERROR;\r
817         srp_path_record_t   *p_srp_path_record;\r
818 \r
819         SRP_ENTER( SRP_DBG_PNP );\r
820 \r
821         while ( g_srp_system_shutdown == FALSE )\r
822         {\r
823                 SRP_TRACE( SRP_DBG_DEBUG, ("Searching for path to %s.\n", p_hba->ioc_info.profile.id_string) );\r
824 \r
825                 cl_spinlock_acquire( &p_hba->path_record_list_lock );\r
826                 p_srp_path_record = (srp_path_record_t *)cl_qlist_head( &p_hba->path_record_list );\r
827                 cl_spinlock_release( &p_hba->path_record_list_lock );\r
828                 if ( p_srp_path_record == (srp_path_record_t *)cl_qlist_end( &p_hba->path_record_list ) )\r
829                 {\r
830                         SRP_TRACE( SRP_DBG_DEBUG, ("No paths to %s found.\n", p_hba->ioc_info.profile.id_string) );\r
831                         break;\r
832                 }\r
833 \r
834                 SRP_TRACE( SRP_DBG_VERBOSE, ("Connecting path to %s.\n", p_hba->ioc_info.profile.id_string) );\r
835 \r
836                 p_hba->p_srp_path_record = p_srp_path_record;\r
837                 status = __srp_connect_sessions( p_hba );\r
838                 if ( status == IB_SUCCESS )\r
839                 {\r
840                         SRP_TRACE( SRP_DBG_DEBUG, ("Path to %s has connected.\n", p_hba->ioc_info.profile.id_string) );\r
841                         break;\r
842                 }\r
843 \r
844                 p_hba->p_srp_path_record = NULL;\r
845                 cl_spinlock_acquire( &p_hba->path_record_list_lock );\r
846                 cl_qlist_remove_item( &p_hba->path_record_list, &p_srp_path_record->list_item );\r
847                 cl_spinlock_release( &p_hba->path_record_list_lock );\r
848                 cl_free( p_srp_path_record );\r
849         }\r
850 \r
851         SRP_EXIT( SRP_DBG_PNP );\r
852 \r
853         return status;\r
854 }\r
855 \r
856 static ib_api_status_t\r
857 __srp_pnp_cb(\r
858         IN              ib_pnp_rec_t                *p_pnp_rec )\r
859 {\r
860         ib_api_status_t                 status = IB_SUCCESS;\r
861         ib_pnp_ioc_rec_t                *p_ioc_rec;\r
862         ib_pnp_ioc_path_rec_t   *p_ioc_path;\r
863         srp_hba_t                               *p_hba;\r
864         srp_path_record_t               *p_srp_path_record;\r
865         \r
866         SRP_ENTER( SRP_DBG_PNP );\r
867 \r
868         p_hba = (srp_hba_t* __ptr64)p_pnp_rec->pnp_context;\r
869         p_ioc_rec = (ib_pnp_ioc_rec_t*)p_pnp_rec;\r
870         p_ioc_path = (ib_pnp_ioc_path_rec_t*)p_pnp_rec;\r
871 \r
872         switch( p_pnp_rec->pnp_event )\r
873         {\r
874                 case IB_PNP_IOC_ADD:\r
875                         SRP_TRACE( SRP_DBG_DEBUG, ("IB_PNP_IOC_ADD for %s.\n", p_ioc_rec->info.profile.id_string) );\r
876 \r
877                         __srp_dump_ioc_info( &p_ioc_rec->info );\r
878 \r
879                         /*\r
880                          * Trap our CA GUID so we filter path notifications\r
881                          * for our bound CA only.\r
882                          */\r
883                         if( p_ioc_rec->ca_guid != p_hba->info.ca_guid )\r
884                         {\r
885                                 SRP_TRACE_EXIT( SRP_DBG_WARN, ("Ignoring CA GUID.\n") );\r
886                                 status = IB_INVALID_GUID;\r
887                                 break;\r
888                         }\r
889 \r
890                         /* Trap our IOC GUID so we can get path notification events. */\r
891                         if( p_ioc_rec->info.profile.ioc_guid != p_hba->info.guid )\r
892                         {\r
893                                 SRP_TRACE_EXIT( SRP_DBG_WARN, ("Ignoring GUID.\n") );\r
894                                 status = IB_INVALID_GUID;\r
895                                 break;\r
896                         }\r
897 \r
898                         if ( __srp_validate_ioc( p_ioc_rec ) == FALSE )\r
899                         {\r
900                                 status = IB_INVALID_GUID;\r
901                                 break;\r
902                         }\r
903 \r
904                         p_hba->ioc_info = p_ioc_rec->info;\r
905                         p_hba->p_svc_entries = cl_zalloc( sizeof(ib_svc_entry_t) * p_hba->ioc_info.profile.num_svc_entries );\r
906                         if ( p_hba->p_svc_entries == NULL )\r
907                         {\r
908                                 SRP_TRACE_EXIT( SRP_DBG_ERROR, ("Insufficient Memory.\n") );\r
909                                 status = IB_INSUFFICIENT_MEMORY;\r
910                                 break;\r
911                         }\r
912 \r
913                         cl_memcpy ( p_hba->p_svc_entries,\r
914                                                 p_ioc_rec->svc_entry_array,\r
915                                                 sizeof(ib_svc_entry_t) * p_hba->ioc_info.profile.num_svc_entries);\r
916 \r
917                         SRP_TRACE( SRP_DBG_VERBOSE, ("Found %d Service Entries.\n", p_hba->ioc_info.profile.num_svc_entries));\r
918                         break;\r
919 \r
920                 case IB_PNP_IOC_REMOVE:\r
921                         SRP_TRACE( SRP_DBG_DEBUG, ("IB_PNP_IOC_REMOVE for %s.\n", p_hba->ioc_info.profile.id_string) );\r
922 \r
923                         CL_ASSERT( p_pnp_rec->guid == p_hba->info.guid );\r
924 \r
925                         SRP_TRACE( SRP_DBG_DEBUG, ("Hey!!! Our IOC went away.\n") );\r
926 \r
927                         __srp_disconnect_sessions( p_hba, FALSE );\r
928                         __srp_remove_path_records( p_hba );\r
929                         SRP_TRACE( SRP_DBG_VERBOSE, ("HBA Object ref_cnt = %d\n", p_hba->obj.ref_cnt) );\r
930                         break;\r
931 \r
932                 case IB_PNP_IOC_PATH_ADD:\r
933                         SRP_TRACE( SRP_DBG_DEBUG,\r
934                                 ("IB_PNP_IOC_PATH_ADD (slid:%d dlid:%d) for %s.\n",\r
935                                 p_ioc_path->path.slid,\r
936                                 p_ioc_path->path.dlid,\r
937                                 p_hba->ioc_info.profile.id_string));\r
938 \r
939                         p_srp_path_record = __srp_add_path( p_hba, &p_ioc_path->path );\r
940                         if ( p_srp_path_record == NULL )\r
941                         {\r
942                                 status = IB_INSUFFICIENT_MEMORY;\r
943                                 break;\r
944                         }\r
945 \r
946                         if ( p_hba->p_srp_path_record == NULL )\r
947                         {\r
948                                 SRP_TRACE( SRP_DBG_VERBOSE, ("Connecting new path to %s.\n", p_hba->ioc_info.profile.id_string) );\r
949                                 status = __srp_connect_path( p_hba );\r
950                         }\r
951                         break;\r
952 \r
953                 case IB_PNP_IOC_PATH_REMOVE:\r
954                         SRP_TRACE( SRP_DBG_DEBUG,\r
955                                 ("IB_PNP_IOC_PATH_REMOVE (slid:%d dlid:%d) for %s.\n",\r
956                                 p_ioc_path->path.slid,\r
957                                 p_ioc_path->path.dlid,\r
958                                 p_hba->ioc_info.profile.id_string));\r
959 \r
960                         p_srp_path_record = __srp_remove_path( p_hba, &p_ioc_path->path );\r
961                         if ( p_srp_path_record != NULL )\r
962                         {\r
963                                 if ( p_srp_path_record == p_hba->p_srp_path_record )\r
964                                 {\r
965                                         SRP_TRACE( SRP_DBG_VERBOSE,\r
966                                                 ("Current path to %s has been lost.\n",\r
967                                                  p_hba->ioc_info.profile.id_string) );\r
968 \r
969                                         if ( g_srp_system_shutdown == FALSE )\r
970                                         {\r
971                                                 __srp_disconnect_sessions( p_hba, TRUE );\r
972                                                 status = __srp_connect_path( p_hba );\r
973                                         }\r
974                                         else\r
975                                         {\r
976                                                 __srp_disconnect_sessions( p_hba, FALSE );\r
977                                         }\r
978                                 }\r
979 \r
980                                 cl_free( p_srp_path_record );\r
981                         }\r
982                         break;\r
983 \r
984                 default:\r
985                         CL_ASSERT( p_pnp_rec->pnp_event == IB_PNP_IOC_ADD ||\r
986                                 p_pnp_rec->pnp_event == IB_PNP_IOC_REMOVE ||\r
987                                 p_pnp_rec->pnp_event == IB_PNP_IOC_PATH_ADD ||\r
988                                 p_pnp_rec->pnp_event == IB_PNP_IOC_PATH_REMOVE );\r
989                         break;\r
990         }\r
991 \r
992         SRP_EXIT( SRP_DBG_PNP );\r
993         return status;\r
994 }\r