[SRP] fixes the BSOD when SRPT disconnects.
[mirror/winof/.git] / ulp / srp / kernel / srp_connection.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 #include "srp_data_path.h"\r
34 #include "srp_debug.h"\r
35 #if defined(EVENT_TRACING)\r
36 #ifdef offsetof\r
37 #undef offsetof\r
38 #endif\r
39 #include "srp_connection.tmh"\r
40 #endif\r
41 #include "srp_event.h"\r
42 #include "srp_hca.h"\r
43 #include "srp_session.h"\r
44 \r
45 #include "srp.h"\r
46 #include "srp_login_req.h"\r
47 #include "srp_login_rsp.h"\r
48 #include "srp_login_rej.h"\r
49 \r
50 #include "srp_connection.h"\r
51 \r
52 #include <complib/cl_math.h>\r
53 \r
54 #if DBG\r
55 \r
56 extern void* gp_session[SRP_MAX_SERVICE_ENTRIES];\r
57 \r
58 #endif\r
59 \r
60 /* __srp_create_cqs */\r
61 /*!\r
62 Creates the send/recv completion queues to be used by this connection\r
63 \r
64 @param p_srp_connection - pointer to the connection structure\r
65 @param p_hca            - pointer to the hca structure used by the connection\r
66 @param p_session        - context passed to callback functions\r
67 \r
68 @return - result of cq creation\r
69 */\r
70 static\r
71 ib_api_status_t\r
72 __srp_create_cqs(\r
73         IN OUT  srp_connection_t    *p_srp_connection,\r
74         IN      srp_hca_t           *p_hca,\r
75         IN      p_srp_session_t     p_session )\r
76 {\r
77         ib_api_status_t status;\r
78         ib_cq_create_t  cq_create;\r
79         ib_al_ifc_t             *p_ifc;\r
80 \r
81         SRP_ENTER( SRP_DBG_PNP );\r
82 \r
83         p_ifc = &p_hca->p_hba->ifc;\r
84 \r
85         // Create Send CQ\r
86         cq_create.size = SRP_DEFAULT_SEND_Q_DEPTH;\r
87         cq_create.pfn_comp_cb = srp_send_completion_cb;\r
88         cq_create.h_wait_obj = NULL;\r
89 \r
90         status = p_ifc->create_cq( p_hca->h_ca,\r
91                                                    &cq_create,\r
92                                                    p_session,\r
93                                                    srp_async_event_handler_cb,\r
94                                                    &p_srp_connection->h_send_cq );\r
95         if( status != IB_SUCCESS )\r
96         {\r
97                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
98                         ("Cannot Create Send Completion Queue. Status = %d\n", status) );\r
99                 goto exit;\r
100         }\r
101 \r
102         // Create Receive CQ\r
103         cq_create.size = SRP_DEFAULT_RECV_Q_DEPTH;\r
104         cq_create.pfn_comp_cb = srp_recv_completion_cb;\r
105         cq_create.h_wait_obj = NULL;\r
106 \r
107         status = p_ifc->create_cq( p_hca->h_ca,\r
108                                                    &cq_create,\r
109                                                    p_session,\r
110                                                    srp_async_event_handler_cb,\r
111                                                    &p_srp_connection->h_recv_cq );\r
112         if( status != IB_SUCCESS )\r
113         {\r
114                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
115                         ("Cannot Create Receive Completion Queue. Status = %d\n", status) );\r
116         }\r
117 \r
118 exit:\r
119         SRP_EXIT( SRP_DBG_PNP );\r
120 \r
121         return ( status );\r
122 }\r
123 \r
124 /* __srp_create_qp */\r
125 /*!\r
126 Creates the queue pair to be used by this connection\r
127 \r
128 @param p_srp_connection - pointer to the connection structure\r
129 @param p_hca            - pointer to the hca structure used by the connection\r
130 @param p_session        - context passed to callback functions\r
131 \r
132 @return - result of qp creation\r
133 */\r
134 static\r
135 ib_api_status_t\r
136 __srp_create_qp(\r
137         IN OUT  srp_connection_t    *p_srp_connection,\r
138         IN      srp_hca_t           *p_hca,\r
139         IN      p_srp_session_t     p_session )\r
140 {\r
141         ib_api_status_t status;\r
142         ib_qp_create_t  qp_create;\r
143         ib_al_ifc_t             *p_ifc;\r
144 \r
145         SRP_ENTER( SRP_DBG_PNP );\r
146 \r
147         p_ifc = &p_hca->p_hba->ifc;\r
148 \r
149         // Create QP\r
150         cl_memclr( &qp_create, sizeof(qp_create) );\r
151         qp_create.qp_type = IB_QPT_RELIABLE_CONN;\r
152         qp_create.sq_depth = SRP_DEFAULT_SEND_Q_DEPTH;\r
153         qp_create.rq_depth = SRP_DEFAULT_RECV_Q_DEPTH;\r
154         qp_create.sq_sge = 1;\r
155         qp_create.rq_sge = 1;\r
156         qp_create.h_sq_cq = p_srp_connection->h_send_cq;\r
157         qp_create.h_rq_cq = p_srp_connection->h_recv_cq;\r
158         qp_create.sq_signaled = FALSE;//TRUE;\r
159 \r
160         status = p_ifc->create_qp( p_hca->h_pd,\r
161                                                    &qp_create,\r
162                                                    p_session,\r
163                                                    srp_async_event_handler_cb,\r
164                                                    &p_srp_connection->h_qp );\r
165         if ( status != IB_SUCCESS )\r
166         {\r
167                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
168                         ("Cannot Create Queue Pair. Status = %d\n", status) );\r
169         }\r
170 \r
171         SRP_EXIT( SRP_DBG_PNP );\r
172 \r
173         return ( status );\r
174 }\r
175 \r
176 static\r
177 cl_status_t\r
178 __srp_create_wc_free_list(\r
179         IN OUT  srp_connection_t    *p_connection,\r
180         IN      uint32_t            completion_count )\r
181 {\r
182         cl_status_t status = CL_SUCCESS;\r
183         ib_wc_t     *p_wc;\r
184         uint32_t    i;\r
185 \r
186         SRP_ENTER( SRP_DBG_PNP );\r
187 \r
188         p_connection->p_wc_array = cl_zalloc( sizeof( ib_wc_t ) * completion_count );\r
189         if ( p_connection->p_wc_array == NULL )\r
190         {\r
191                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
192                         ("Failed to allocate %d work completions.\n",  completion_count) );\r
193                 status = CL_INSUFFICIENT_MEMORY;\r
194                 goto exit;\r
195         }\r
196 \r
197         p_wc = p_connection->p_wc_array;\r
198 \r
199         for ( i = 1; i < completion_count; i++, p_wc++ )\r
200         {\r
201                 p_wc->p_next = (p_wc + 1);\r
202         }\r
203 \r
204         p_connection->p_wc_free_list = p_connection->p_wc_array;\r
205 \r
206 exit:\r
207         SRP_EXIT( SRP_DBG_PNP );\r
208 \r
209         return ( status );\r
210 }\r
211 \r
212 \r
213 /* __srp_cm_request_cb */\r
214 /*!\r
215 Callback for a connect request - not used by SRP - We initiate connections\r
216 \r
217 @param p_cm_request - pointer to the connect request structure\r
218 \r
219 @return - none\r
220 */\r
221 static\r
222 void\r
223 __srp_cm_request_cb(\r
224         IN  ib_cm_req_rec_t     *p_cm_request)\r
225 {\r
226         SRP_ENTER( SRP_DBG_PNP );\r
227 \r
228         UNUSED_PARAM ( p_cm_request );\r
229 \r
230         SRP_EXIT( SRP_DBG_PNP );\r
231 }\r
232 \r
233 /* __srp_cm_apr_cb */\r
234 /*!\r
235 Callback for alternate path response - not used by SRP\r
236 \r
237 @param p_cm_apr_rec - pointer to the alternate path response structure\r
238 \r
239 @return - none\r
240 */\r
241 static\r
242 void\r
243 __srp_cm_apr_cb(\r
244         IN  ib_cm_apr_rec_t *p_cm_apr_rec )\r
245 {\r
246         SRP_ENTER( SRP_DBG_PNP );\r
247 \r
248         UNUSED_PARAM( p_cm_apr_rec );\r
249 \r
250         SRP_EXIT( SRP_DBG_PNP );\r
251 }\r
252 \r
253 /* __srp_cm_mra_cb */\r
254 /*!\r
255 Callback for message received acknowledgement - ignored by SRP - wait for connect reply\r
256 \r
257 @param p_cm_mra_rec - pointer to the message received acknowledgement structure\r
258 \r
259 @return - none\r
260 */\r
261 static\r
262 void\r
263 __srp_cm_mra_cb(\r
264         IN  ib_cm_mra_rec_t     *p_cm_mra_rec)\r
265 {\r
266         SRP_ENTER( SRP_DBG_PNP );\r
267 \r
268         UNUSED_PARAM ( p_cm_mra_rec );\r
269 \r
270         SRP_EXIT( SRP_DBG_PNP );\r
271 }\r
272 \r
273 /* __srp_cm_dreq_cb */\r
274 /*!\r
275 Callback for disconnect request from the target\r
276 Initiates the disconnect for the session\r
277 \r
278 TODO:\r
279 \r
280 @param p_cm_dreq_rec - pointer to the disconnect request structure\r
281 \r
282 @return - none\r
283 */\r
284 static\r
285 void\r
286 __srp_cm_dreq_cb(\r
287         IN  ib_cm_dreq_rec_t    *p_cm_dreq_rec )\r
288 {\r
289         srp_session_t   *p_srp_session = (srp_session_t* VOID_PTR64)p_cm_dreq_rec->qp_context;\r
290         srp_hba_t       *p_hba = p_srp_session->p_hba;\r
291 \r
292         SRP_ENTER( SRP_DBG_PNP );\r
293 \r
294         cl_obj_lock( &p_srp_session->obj );\r
295 \r
296         if (p_srp_session->connection.state == SRP_CONNECTED)\r
297         {\r
298                 SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP,\r
299                         ("**** SRP_CONNECTED => SRP_CONNECT_FAILURE. \n") );\r
300                 p_srp_session->connection.state = SRP_CONNECT_FAILURE;\r
301                 cl_obj_unlock( &p_srp_session->obj );\r
302         }\r
303         else  // since the connection is no longer there, just exit\r
304         {\r
305                 cl_obj_unlock( &p_srp_session->obj );\r
306                 SRP_PRINT( TRACE_LEVEL_VERBOSE, SRP_DBG_PNP,\r
307                         ("**** NOT SRP_CONNECTED *****. connection state = %d\n", p_srp_session->connection.state) );\r
308                 SRP_EXIT( SRP_DBG_PNP );\r
309                 return; \r
310         }\r
311 \r
312         SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_PNP,\r
313                 ("Target has issued a disconnect request for Session %d ref_cnt = %d.\n",\r
314                                                 p_srp_session->target_id,\r
315                                                 p_srp_session->obj.ref_cnt) );\r
316 \r
317         if( !p_hba->adapter_stopped )\r
318         {\r
319                 srp_session_failed( p_srp_session );\r
320         }\r
321 \r
322         SRP_EXIT( SRP_DBG_PNP );\r
323 }\r
324 \r
325 /* __srp_cm_reply_cb */\r
326 /*!\r
327 Callback for connect reply from the target\r
328 The target has accepted our connect/login request\r
329 \r
330 @param p_cm_reply - pointer to the connect reply structure\r
331 \r
332 @return - none\r
333 */\r
334 static\r
335 void\r
336 __srp_cm_reply_cb(\r
337         IN  ib_cm_rep_rec_t     *p_cm_reply)\r
338 {\r
339         srp_session_t           *p_srp_session = (srp_session_t* VOID_PTR64)p_cm_reply->qp_context;\r
340         srp_connection_t        *p_connection;\r
341         srp_login_rsp_t         *p_srp_login_rsp = (srp_login_rsp_t* VOID_PTR64)p_cm_reply->p_rep_pdata;\r
342         ib_api_status_t         status;\r
343         union\r
344         {\r
345                 ib_cm_mra_t             cm_mra;\r
346                 ib_cm_rtu_t             cm_rtu;\r
347                 ib_cm_rej_t             cm_rej;\r
348 \r
349         }       u;\r
350         cl_status_t                     cl_status;\r
351         ib_al_ifc_t                     *p_ifc;\r
352 \r
353         SRP_ENTER( SRP_DBG_PNP );\r
354 \r
355         p_ifc = &p_srp_session->p_hba->ifc;\r
356         p_connection = &p_srp_session->connection;\r
357 \r
358         set_srp_login_response_from_network_to_host( p_srp_login_rsp );\r
359         p_connection->descriptor_format = get_srp_login_response_supported_data_buffer_formats( p_srp_login_rsp );\r
360 \r
361         p_connection->request_limit      =\r
362                 MIN( get_srp_login_response_request_limit_delta( p_srp_login_rsp ), SRP_DEFAULT_RECV_Q_DEPTH );\r
363         \r
364         if( ib_ioc_profile_get_vend_id( &p_srp_session->p_hba->ioc_info.profile) == 0x00066a &&\r
365                 cl_ntoh32( p_srp_session->p_hba->ioc_info.profile.subsys_id ) == 0x38 )\r
366         {\r
367                 /* workaround for FVIC */\r
368                 p_connection->request_limit /= 2;\r
369         }\r
370 \r
371         p_connection->max_limit = p_connection->request_limit;\r
372         p_connection->request_threashold = 2;\r
373 #if DBG\r
374         p_srp_session->x_req_limit = p_connection->request_limit;\r
375 #endif\r
376 \r
377         p_connection->send_queue_depth   = p_connection->request_limit;\r
378         p_connection->recv_queue_depth   = p_connection->request_limit;\r
379         p_connection->init_to_targ_iu_sz = get_srp_login_response_max_init_to_targ_iu( p_srp_login_rsp );\r
380         p_connection->targ_to_init_iu_sz = get_srp_login_response_max_targ_to_init_iu( p_srp_login_rsp );\r
381 \r
382         p_connection->signaled_send_completion_count = 32;\r
383         \r
384         if (( p_connection->descriptor_format & DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) == DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS )\r
385         {\r
386                 p_connection->max_scatter_gather_entries =\r
387                                 ( MIN( SRP_MAX_IU_SIZE, p_connection->init_to_targ_iu_sz ) - offsetof( srp_cmd_t, additional_cdb )- sizeof(srp_memory_table_descriptor_t)) / sizeof( srp_memory_descriptor_t );\r
388         }\r
389         else if (( p_connection->descriptor_format & DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ) == DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR )\r
390         {\r
391                 p_connection->max_scatter_gather_entries =\r
392                                 ((p_connection->init_to_targ_iu_sz - offsetof( srp_cmd_t, additional_cdb )) / sizeof( srp_memory_descriptor_t )) ? 1 : 0;\r
393         }\r
394         else /* not reported any descriptor format */\r
395         {\r
396                 SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG,\r
397                         ("Target does not support valid descriptor formats\n") );\r
398                 goto rej;\r
399         }\r
400         SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_DEBUG,\r
401                         ("Request Limit = %d, SendQ Depth = %d, RecvQDepth = %d, "\r
402                         "ItoT size = %d, TtoI size = %d, Max S/G = %d\n",\r
403                         p_connection->request_limit,\r
404                         p_connection->send_queue_depth,\r
405                         p_connection->recv_queue_depth,\r
406                         p_connection->init_to_targ_iu_sz,\r
407                         p_connection->targ_to_init_iu_sz,\r
408                         p_connection->max_scatter_gather_entries) );\r
409 \r
410         /* will be used in srp_find_adapter to calculate NumberOfPhysicalBreaks */\r
411         p_srp_session->p_hba->max_sg = p_connection->max_scatter_gather_entries;\r
412 \r
413         u.cm_mra.svc_timeout = 0x08;\r
414         u.cm_mra.p_mra_pdata = NULL;\r
415         u.cm_mra.mra_length = 0;\r
416 \r
417         status = p_ifc->cm_mra( p_cm_reply->h_cm_rep, &u.cm_mra );\r
418         if ( status != IB_SUCCESS )\r
419         {\r
420                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
421                         ("Cannot Send MRA. Status = %d\n", status) );\r
422                 goto rej;\r
423         }\r
424 \r
425         status = p_ifc->modify_cq( p_connection->h_send_cq, &p_connection->send_queue_depth );\r
426         if ( status != IB_SUCCESS )\r
427         {\r
428                 SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_PNP,\r
429                         ("Cannot Modify Send Completion Queue Depth. Status = %d\n", status) );\r
430         }\r
431 \r
432         status = p_ifc->modify_cq( p_connection->h_recv_cq, &p_connection->recv_queue_depth );\r
433         if ( status != IB_SUCCESS )\r
434         {\r
435                 SRP_PRINT( TRACE_LEVEL_WARNING, SRP_DBG_PNP,\r
436                         ("Cannot Modify Recv Completion Queue Depth. Status = %d\n", status) );\r
437         }\r
438 \r
439         cl_status = __srp_create_wc_free_list( p_connection, (p_connection->request_limit * 2) );/* Send/Recv */\r
440         if ( cl_status != CL_SUCCESS )\r
441         {\r
442                 goto rej;\r
443         }\r
444 \r
445         status = srp_init_descriptors( &p_srp_session->descriptors,\r
446                                                                    p_connection->request_limit,\r
447                                                                    p_connection->targ_to_init_iu_sz,\r
448                                                                    &p_srp_session->p_hba->ifc,\r
449                                                                    p_srp_session->hca.h_pd,\r
450                                                                    p_connection->h_qp,\r
451                                                                    p_srp_session->hca.lkey );\r
452         if ( status != IB_SUCCESS )\r
453         {\r
454                 goto err_init_desc;\r
455         }\r
456 \r
457         u.cm_rtu.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE;\r
458 \r
459         /* Have to set to 0 to indicate not to modify because Tavor doesn't support this */\r
460         u.cm_rtu.sq_depth = 0 /*p_connection->request_limit*/;\r
461         u.cm_rtu.rq_depth = 0 /*p_connection->request_limit*/;\r
462 \r
463         u.cm_rtu.p_rtu_pdata = NULL;\r
464         u.cm_rtu.rtu_length = 0;\r
465         u.cm_rtu.pfn_cm_apr_cb = __srp_cm_apr_cb;\r
466         u.cm_rtu.pfn_cm_dreq_cb = __srp_cm_dreq_cb;\r
467 \r
468         status = p_ifc->cm_rtu( p_cm_reply->h_cm_rep, &u.cm_rtu );\r
469         if ( status != IB_SUCCESS )\r
470         {\r
471                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
472                         ("Cannot Send RTU. Status = %d\n", status) );\r
473                 goto err_send_rtu;\r
474         }\r
475 \r
476         p_connection->state = SRP_CONNECTED;\r
477 \r
478         status = p_ifc->rearm_cq( p_connection->h_send_cq, FALSE );\r
479         if ( status != IB_SUCCESS)\r
480         {\r
481                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
482                         ("ib_rearm_cq() for send cq failed!, status 0x%x", status) );\r
483 \r
484                 // TODO: Kill session and inform port driver link down storportnotification\r
485                 goto err_send_rtu;\r
486         }\r
487 \r
488         status = p_ifc->rearm_cq( p_connection->h_recv_cq, FALSE );\r
489         if ( status != IB_SUCCESS)\r
490         {\r
491                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
492                         ("ib_rearm_cq() for recv failed!, status 0x%x", status) );\r
493 \r
494                 // TODO: Kill session and inform port driver link down storportnotification\r
495                 goto err_send_rtu;\r
496         }\r
497         goto exit;\r
498 \r
499 err_send_rtu:   \r
500         // the rest will be cleaned up in srp_session_login\r
501 \r
502 err_init_desc:\r
503         cl_free( p_connection->p_wc_array );\r
504         p_connection->p_wc_array = NULL;\r
505         p_connection->p_wc_free_list = NULL;\r
506 \r
507 rej:\r
508         p_connection->state = SRP_CONNECT_FAILURE;\r
509         cl_memclr( &u.cm_rej, sizeof(u.cm_rej) );\r
510         u.cm_rej.rej_status = IB_REJ_INSUF_RESOURCES;\r
511         p_ifc->cm_rej( p_cm_reply->h_cm_rep, &u.cm_rej );\r
512 \r
513 exit:\r
514         cl_status = cl_event_signal( &p_connection->conn_req_event );\r
515 \r
516         SRP_EXIT( SRP_DBG_PNP );\r
517 }\r
518 \r
519 \r
520 /* __srp_cm_rej_cb */\r
521 /*!\r
522 Callback for connect reject from the target\r
523 The target has rejected our connect/login request\r
524 \r
525 @param p_cm_reject - pointer to the connect reject structure\r
526 \r
527 @return - none\r
528 */\r
529 static\r
530 void\r
531 __srp_cm_rej_cb(\r
532         IN  ib_cm_rej_rec_t     *p_cm_reject)\r
533 {\r
534         srp_session_t       *p_srp_session = (srp_session_t* VOID_PTR64)p_cm_reject->qp_context;\r
535         srp_connection_t    *p_connection;\r
536         srp_login_rej_t     *p_srp_login_rej = (srp_login_rej_t* VOID_PTR64)p_cm_reject->p_rej_pdata;\r
537         cl_status_t         cl_status;\r
538 \r
539         SRP_ENTER( SRP_DBG_PNP );\r
540 \r
541         p_connection = &p_srp_session->connection;\r
542 \r
543         if( p_srp_login_rej )\r
544         {\r
545                 set_srp_login_reject_from_network_to_host( p_srp_login_rej ); // <-- Is this coming back NULL?\r
546                 p_connection->reject_reason = get_srp_login_reject_reason( p_srp_login_rej );\r
547 \r
548                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
549                         ("Login Rejected. IBT Code = 0x%x, SRP Code = 0x%x\n",\r
550                         p_cm_reject->rej_status, p_connection->reject_reason ) );\r
551                 switch( p_connection->reject_reason )\r
552                 {\r
553                         case LIREJ_INIT_TO_TARG_IU_LENGTH_TOO_LARGE:\r
554                                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
555                                         ("REQUESTED IU_SIZE %d\n",\r
556                                          p_connection->req_max_iu_msg_size ));\r
557                                 break;\r
558                         case LIREJ_UNSUPPORTED_DATA_BUFFER_DESCRIPTOR_FORMAT:\r
559                                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
560                                         ("REQUESTED DESC FORMAT: %#x, SUPPORTED FORMAT %#x\n",\r
561                                         p_connection->descriptor_format, \r
562                                         get_srp_login_reject_supported_data_buffer_formats(p_srp_login_rej) ));\r
563                                         __srp_issue_session_login( p_connection, (srp_hca_t *)&p_srp_session->hca, p_connection->ioc_max_send_msg_depth );\r
564                                         return;\r
565                         default:\r
566                                 break;\r
567                 }\r
568         }\r
569         else\r
570         {\r
571                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
572                         ("Login Rejected. IBT Code = 0x%x\n",\r
573                         p_cm_reject->rej_status) );\r
574 }\r
575         p_connection->state = SRP_CONNECT_FAILURE;\r
576 \r
577         cl_status = cl_event_signal( &p_connection->conn_req_event );\r
578 \r
579         SRP_EXIT( SRP_DBG_PNP );\r
580 }\r
581 \r
582 /* __srp_issue_session_login */\r
583 /*!\r
584 Initializes and issues a login/cm connect request to the target\r
585 \r
586 @param p_connection   - pointer to the connection structure\r
587 @param p_hca          - pointer to the hca structure used by this connection\r
588 @param send_msg_depth - initial request limit delta value\r
589 \r
590 @return - result of login/cm connect request operations\r
591 */\r
592 #pragma warning( disable : 4748)\r
593 #pragma optimize( "", off )\r
594 static\r
595 ib_api_status_t\r
596 __srp_issue_session_login(\r
597         IN OUT  srp_connection_t    *p_connection,\r
598         IN      srp_hca_t           *p_hca,\r
599         IN      uint8_t             send_msg_depth )\r
600 {\r
601         ib_api_status_t status;\r
602         ib_cm_req_t     cm_req;\r
603         srp_login_req_t login_req;\r
604 \r
605         SRP_ENTER( SRP_DBG_PNP );\r
606 \r
607         cl_memclr( &cm_req, sizeof(ib_cm_req_t) );\r
608 \r
609         cm_req.svc_id = p_connection->service_id;\r
610 \r
611         cm_req.flags = 0; // event used instead of IB_FLAGS_SYNC\r
612         cm_req.max_cm_retries = 8;\r
613         cm_req.p_primary_path = p_connection->p_path_rec;\r
614         \r
615         /*already tried to login before and failed ? */\r
616         if ( !p_connection->reject_reason )\r
617         {\r
618                 p_connection->descriptor_format = DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR | DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS;\r
619         }\r
620         else if ( p_connection->reject_reason == LIREJ_UNSUPPORTED_DATA_BUFFER_DESCRIPTOR_FORMAT )\r
621         {\r
622                 p_connection->descriptor_format = DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR;\r
623         }\r
624         else\r
625         {\r
626                 p_connection->state = SRP_CONNECT_FAILURE;\r
627                 status = IB_ERROR;\r
628                 goto exit;\r
629         }\r
630         p_connection->req_max_iu_msg_size = ( p_connection->ioc_max_send_msg_size >= SRP_MAX_IU_SIZE ) ? SRP_MAX_IU_SIZE: p_connection->ioc_max_send_msg_size;\r
631         SRP_PRINT( TRACE_LEVEL_INFORMATION, SRP_DBG_ERROR, \r
632                 ( "(init_to_targ_iu_sz requested)  req_max_iu_msg_size %d, (from profile) ioc_max_send_msg_size %d\n", \r
633                 p_connection->req_max_iu_msg_size, p_connection->ioc_max_send_msg_size ));\r
634         /*\r
635            Build SRP Login request\r
636          */\r
637         setup_srp_login_request( &login_req,\r
638                                                          0, /* tag */\r
639                                                          p_connection->req_max_iu_msg_size,\r
640                                                          p_connection->descriptor_format,\r
641                                                          MCA_TERMINATE_EXISTING,\r
642                                                          &p_connection->init_port_id,\r
643                                                          &p_connection->targ_port_id );\r
644         set_srp_login_request_from_host_to_network(&login_req);\r
645 \r
646         cm_req.p_req_pdata = (const uint8_t *)&login_req;\r
647         cm_req.req_length = (uint8_t)get_srp_login_request_length( &login_req );\r
648 \r
649         cm_req.qp_type = IB_QPT_RELIABLE_CONN;\r
650         cm_req.h_qp = p_connection->h_qp;\r
651 \r
652         /* The maximum number of outstanding RDMA read/atomic operations. */\r
653         status = srp_get_responder_resources( p_hca, &cm_req.resp_res );\r
654         if ( status != IB_SUCCESS )\r
655         {\r
656                 goto exit;\r
657         }\r
658 \r
659         cm_req.init_depth = send_msg_depth;\r
660 \r
661         cm_req.remote_resp_timeout = ib_path_rec_pkt_life( p_connection->p_path_rec ) + 1;\r
662         cm_req.flow_ctrl = FALSE;\r
663         cm_req.local_resp_timeout = ib_path_rec_pkt_life( p_connection->p_path_rec ) + 1;\r
664         cm_req.retry_cnt = 1;\r
665         cm_req.rnr_nak_timeout = 0; /* 655.36 ms */\r
666         cm_req.rnr_retry_cnt = 6;\r
667 \r
668         cm_req.pfn_cm_rep_cb = __srp_cm_reply_cb;\r
669         cm_req.pfn_cm_req_cb = NULL; /* Set only for P2P */\r
670         cm_req.pfn_cm_mra_cb = __srp_cm_mra_cb;\r
671         cm_req.pfn_cm_rej_cb = __srp_cm_rej_cb;\r
672 \r
673         cm_req.pkey = p_connection->p_path_rec->pkey;\r
674 \r
675         status = p_hca->p_hba->ifc.cm_req( &cm_req );\r
676         if ( status == IB_SUCCESS )\r
677         {\r
678                 p_connection->state = SRP_CONNECT_REQUESTED;\r
679         }\r
680         else\r
681         {\r
682                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
683                         ("Cannot Send Connect Request. Status = %d\n", status) );\r
684                 p_connection->state = SRP_CONNECT_FAILURE;\r
685         }\r
686 \r
687 exit:\r
688         SRP_EXIT( SRP_DBG_PNP );\r
689 \r
690         return ( status );\r
691 }\r
692 #pragma optimize( "", on )\r
693 #pragma warning( default : 4748)\r
694 \r
695 /* srp_init_connection */\r
696 /*!\r
697 Initializes a connection structure\r
698 \r
699 @param p_connection   - pointer to the connection structure\r
700 @param p_profile      - Pointer to IOC profile.\r
701 @param ca_guid        - Local CA GUID to use in as initiator GUID.\r
702 @param ext_id         - Initiator and target extension ID.\r
703 @param p_path_rec     - pointer to the path to the target\r
704 @param service_id     - service id to which we want to connect\r
705 \r
706 @return - always success (for now)\r
707 */\r
708 ib_api_status_t\r
709 srp_init_connection(\r
710         IN      OUT     srp_connection_t                *p_connection,\r
711         IN              ib_ioc_profile_t* const p_profile,\r
712         IN              net64_t                                 ca_guid,\r
713         IN              net64_t                                 ext_id,\r
714         IN      ib_path_rec_t           *p_path_rec,\r
715         IN              ib_net64_t                              service_id )\r
716 {\r
717         SRP_ENTER( SRP_DBG_PNP );\r
718 \r
719         cl_memclr( p_connection, sizeof(*p_connection) );\\r
720 \r
721         p_connection->initialized = TRUE;\r
722 \r
723         p_connection->state = SRP_NOT_CONNECTED;\r
724 \r
725         p_connection->p_path_rec = p_path_rec;\r
726         switch( p_profile->io_class )\r
727         {\r
728         case SRP_IO_CLASS_R10:\r
729                 p_connection->init_port_id.field1 = ca_guid;\r
730                 p_connection->init_port_id.field2 = ext_id;\r
731                 p_connection->targ_port_id.field1 = p_profile->ioc_guid;\r
732                 p_connection->targ_port_id.field2 = ext_id;\r
733                 break;\r
734 \r
735         case SRP_IO_CLASS:\r
736                 p_connection->init_port_id.field1 = ext_id;\r
737                 p_connection->init_port_id.field2 = ca_guid;\r
738                 p_connection->targ_port_id.field1 = ext_id;\r
739                 p_connection->targ_port_id.field2 = p_profile->ioc_guid;\r
740                 break;\r
741 \r
742         default:\r
743                 return IB_INVALID_PARAMETER;\r
744         }\r
745         p_connection->service_id = service_id;\r
746         p_connection->send_queue_depth = SRP_DEFAULT_SEND_Q_DEPTH;\r
747         p_connection->recv_queue_depth = SRP_DEFAULT_RECV_Q_DEPTH;\r
748 \r
749         SRP_EXIT( SRP_DBG_PNP );\r
750 \r
751         return ( IB_SUCCESS );\r
752 }\r
753 \r
754 /* srp_connect */\r
755 /*!\r
756 Orchestrates the processing required to connect to a target device\r
757 \r
758 @param p_connection        - pointer to the connection structure\r
759 @param p_hca               - pointer to the hca structure used by this connection\r
760 @param send_msg_depth      - initial request limit delta value\r
761 @param p_session           - context passed to callback functions\r
762 \r
763 @return -  result of connect operations\r
764 */\r
765 ib_api_status_t\r
766 srp_connect(\r
767         IN OUT  srp_connection_t    *p_connection,\r
768         IN      srp_hca_t           *p_hca,\r
769         IN      uint8_t             send_msg_depth,\r
770         IN      p_srp_session_t     p_session )\r
771 {\r
772         ib_api_status_t status;\r
773         cl_status_t     cl_status;\r
774 \r
775         SRP_ENTER( SRP_DBG_PNP );\r
776 \r
777         p_connection->ioc_max_send_msg_size =\r
778                 cl_ntoh32 (p_session->p_hba->ioc_info.profile.send_msg_size);\r
779         p_connection->ioc_max_send_msg_depth = send_msg_depth;\r
780         p_connection->reject_reason = 0;\r
781 \r
782         status = __srp_create_cqs( p_connection, p_hca, p_session );\r
783         if ( status != IB_SUCCESS )\r
784         {\r
785                 goto exit;\r
786         }\r
787 \r
788         status = __srp_create_qp( p_connection, p_hca, p_session );\r
789         if ( status != IB_SUCCESS )\r
790         {\r
791                 goto exit;\r
792         }\r
793 \r
794         cl_status = cl_event_init( &p_connection->conn_req_event, TRUE );\r
795         if ( cl_status != CL_SUCCESS )\r
796         {\r
797                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
798                         ("Cannot Initialize Connect Request Event. Status = %d\n", cl_status) );\r
799                 status = cl_status;\r
800                 goto exit;\r
801         }\r
802 \r
803         status = __srp_issue_session_login( p_connection, p_hca, send_msg_depth );\r
804         if ( status != IB_SUCCESS )\r
805         {\r
806                 cl_event_destroy( &p_connection->conn_req_event );\r
807                 goto exit;\r
808         }\r
809 \r
810         cl_status = cl_event_wait_on( &p_connection->conn_req_event, EVENT_NO_TIMEOUT, FALSE );\r
811         if ( cl_status != CL_SUCCESS )\r
812         {\r
813                 SRP_PRINT( TRACE_LEVEL_ERROR, SRP_DBG_ERROR,\r
814                         ("Wait On Connect Request Event Failed. Status = %d\n", cl_status) );\r
815                 status = cl_status;\r
816                 cl_event_destroy( &p_connection->conn_req_event );\r
817                 goto exit;\r
818         }\r
819 \r
820         cl_event_destroy( &p_connection->conn_req_event );\r
821 \r
822         if ( p_connection->state != SRP_CONNECTED )\r
823         {\r
824                 status = IB_ERROR;\r
825                 goto exit;\r
826         }\r
827         \r
828         cl_thread_init( &p_session->recovery_thread, \r
829                                         (cl_pfn_thread_callback_t)srp_session_recovery_thread,\r
830                                         (void *)p_session, "srp_thread" );\r
831 #if DBG\r
832         gp_session[p_session->target_id] = p_session;\r
833 #endif\r
834 \r
835 exit:\r
836         SRP_EXIT( SRP_DBG_PNP );\r
837 \r
838         return ( status );\r
839 }\r
840 \r
841 /* srp_free_connection */\r
842 /*!\r
843 Frees connection resources\r
844 \r
845 @param p_connection  - pointer to the connection structure\r
846 \r
847 @return -  none\r
848 */\r
849 void\r
850 srp_free_connection(\r
851         IN  srp_connection_t    *p_srp_connection )\r
852 {\r
853         SRP_ENTER( SRP_DBG_PNP );\r
854 \r
855         if ( p_srp_connection->initialized == TRUE )\r
856         {\r
857                 if ( p_srp_connection->p_wc_array != NULL )\r
858                 {\r
859                         cl_free( p_srp_connection->p_wc_array );\r
860                 }\r
861 \r
862                 cl_event_destroy( &p_srp_connection->conn_req_event );\r
863 \r
864                 cl_memclr( p_srp_connection, sizeof( *p_srp_connection ) );\r
865         }\r
866 \r
867         SRP_EXIT( SRP_DBG_PNP );\r
868 }\r
869 \r
870 \r
871 \r
872 \r