2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
4 * This software is available to you under the OpenIB.org BSD license
\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
11 * - Redistributions of source code must retain the above
\r
12 * copyright notice, this list of conditions and the following
\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
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
33 #include "srp_connection.h"
\r
34 #include "srp_cmd.h"
\r
35 #include "srp_data_path.h"
\r
36 #include "srp_descriptors.h"
\r
37 #include "srp_rsp.h"
\r
38 #include "srp_session.h"
\r
39 #include "srp_tsk_mgmt.h"
\r
41 /* __srp_create_recv_descriptors */
\r
43 Creates the receive descriptors and posts them to the receive queue
\r
45 @param p_descriptors - pointer to the work requests structure
\r
46 @param h_pd - protection domain used for registration of memory
\r
47 @param h_qp - queue pair used to post work requests
\r
49 @return - result of operations
\r
51 static ib_api_status_t
\r
52 __srp_create_recv_descriptors(
\r
53 IN OUT srp_descriptors_t *p_descriptors,
\r
54 IN ib_al_ifc_t* const p_ifc,
\r
55 IN ib_pd_handle_t h_pd,
\r
56 IN ib_qp_handle_t h_qp )
\r
58 ib_api_status_t status = IB_SUCCESS;
\r
59 srp_recv_descriptor_t *p_descriptor;
\r
60 uint8_t *p_data_segment;
\r
61 ib_mr_create_t mr_create;
\r
64 SRP_ENTER( SRP_DBG_PNP );
\r
66 /* Create the array of recv descriptors */
\r
67 p_descriptors->p_recv_descriptors_array =
\r
68 (srp_recv_descriptor_t *)cl_zalloc( p_descriptors->recv_descriptor_count * sizeof(srp_recv_descriptor_t) );
\r
69 if ( p_descriptors->p_recv_descriptors_array == NULL )
\r
71 SRP_TRACE( SRP_DBG_ERROR,
\r
72 ("Failed to allocate %d recv descriptors.\n", p_descriptors->recv_descriptor_count) );
\r
73 status = IB_INSUFFICIENT_MEMORY;
\r
77 /* Create the array of recv data segments */
\r
78 p_descriptors->p_recv_data_segments_array =
\r
79 cl_zalloc( p_descriptors->recv_descriptor_count * p_descriptors->recv_data_segment_size );
\r
80 if ( p_descriptors->p_recv_data_segments_array == NULL )
\r
82 SRP_TRACE( SRP_DBG_ERROR,
\r
83 ("Failed to allocate %d recv data segments of %d length.\n",
\r
84 p_descriptors->recv_descriptor_count,
\r
85 p_descriptors->recv_data_segment_size) );
\r
87 cl_free( p_descriptors->p_recv_descriptors_array );
\r
88 p_descriptors->p_recv_descriptors_array = NULL;
\r
89 status = IB_INSUFFICIENT_MEMORY;
\r
93 /* Register the data segments array memory */
\r
94 mr_create.vaddr = p_descriptors->p_recv_data_segments_array;
\r
95 mr_create.length = p_descriptors->recv_descriptor_count * p_descriptors->recv_data_segment_size;
\r
96 mr_create.access_ctrl = IB_AC_LOCAL_WRITE;
\r
98 status = p_ifc->reg_mem( h_pd,
\r
100 &p_descriptors->recv_lkey,
\r
101 &p_descriptors->recv_rkey,
\r
102 &p_descriptors->h_recv_mr );
\r
103 if ( status != IB_SUCCESS )
\r
105 SRP_TRACE( SRP_DBG_ERROR,
\r
106 ("Failed to register recv data segments. Status = %d.\n", status) );
\r
108 cl_free( p_descriptors->p_recv_data_segments_array );
\r
109 p_descriptors->p_recv_data_segments_array = NULL;
\r
111 cl_free( p_descriptors->p_recv_descriptors_array );
\r
112 p_descriptors->p_recv_descriptors_array = NULL;
\r
116 /* Initialize them and post to receive queue */
\r
117 p_descriptor = p_descriptors->p_recv_descriptors_array;
\r
118 p_data_segment = p_descriptors->p_recv_data_segments_array;
\r
120 for ( i = 0; i < p_descriptors->recv_descriptor_count; i++ )
\r
122 p_descriptor->wr.p_next = NULL;
\r
123 p_descriptor->wr.wr_id = (uint64_t)((void* __ptr64)p_descriptor);
\r
124 p_descriptor->wr.num_ds = 1;
\r
125 p_descriptor->wr.ds_array = p_descriptor->ds;
\r
127 p_descriptor->ds[0].vaddr = (uint64_t)((void* __ptr64)p_data_segment);
\r
128 p_descriptor->ds[0].length = p_descriptors->recv_data_segment_size;
\r
129 p_descriptor->ds[0].lkey = p_descriptors->recv_lkey;
\r
131 p_descriptors->p_recv_descriptors_array[i].p_data_segment = p_data_segment;
\r
133 status = p_ifc->post_recv( h_qp, &p_descriptor->wr, NULL );
\r
134 if ( status != IB_SUCCESS )
\r
136 SRP_TRACE( SRP_DBG_ERROR,
\r
137 ("Failed to post send descriptor. Status = %d.\n", status) );
\r
142 p_data_segment += p_descriptors->recv_data_segment_size;
\r
146 SRP_EXIT( SRP_DBG_PNP );
\r
151 /* srp_init_descriptors */
\r
153 Orchestrates creation of receive descriptor buffers and sent list
\r
155 @param p_descriptors - pointer to the descriptors structure
\r
156 @param recv descriptor_count - number of receive descriptors to create
\r
157 @param recv data_segment_size - size of each receive descriptor's data area
\r
158 @param h_pd - protection domain used for registration of memory
\r
159 @param h_qp - queue pair used to post work requests
\r
161 @return - result of operations
\r
164 srp_init_descriptors(
\r
165 IN OUT srp_descriptors_t *p_descriptors,
\r
166 IN uint32_t recv_descriptor_count,
\r
167 IN uint32_t recv_data_segment_size,
\r
168 IN ib_al_ifc_t* const p_ifc,
\r
169 IN ib_pd_handle_t h_pd,
\r
170 IN ib_qp_handle_t h_qp )
\r
172 ib_api_status_t status;
\r
174 SRP_ENTER( SRP_DBG_PNP );
\r
176 CL_ASSERT( p_descriptors != NULL );
\r
178 cl_memclr( p_descriptors, sizeof(*p_descriptors) );
\r
180 cl_spinlock_init ( &p_descriptors->sent_list_lock );
\r
181 cl_qlist_init( &p_descriptors->sent_descriptors );
\r
183 p_descriptors->initialized = TRUE;
\r
185 p_descriptors->recv_descriptor_count = recv_descriptor_count;
\r
186 p_descriptors->recv_data_segment_size = recv_data_segment_size;
\r
188 status = __srp_create_recv_descriptors( p_descriptors, p_ifc, h_pd, h_qp );
\r
189 if ( status != IB_SUCCESS )
\r
191 srp_destroy_descriptors( p_descriptors );
\r
194 SRP_EXIT( SRP_DBG_PNP );
\r
199 /* srp_destroy_descriptors */
\r
201 Destroys the receive work request buffers
\r
203 @param p_descriptors - pointer to the descriptors structure
\r
205 @return - result of operations
\r
208 srp_destroy_descriptors(
\r
209 IN OUT srp_descriptors_t *p_descriptors )
\r
211 SRP_ENTER( SRP_DBG_PNP );
\r
213 if ( p_descriptors->initialized == TRUE )
\r
215 cl_spinlock_destroy ( &p_descriptors->sent_list_lock );
\r
217 if ( p_descriptors->p_recv_data_segments_array != NULL )
\r
219 cl_free( p_descriptors->p_recv_data_segments_array );
\r
222 if ( p_descriptors->p_recv_descriptors_array != NULL )
\r
224 cl_free( p_descriptors->p_recv_descriptors_array );
\r
227 cl_memclr( p_descriptors, sizeof( *p_descriptors ) );
\r
230 SRP_EXIT( SRP_DBG_PNP );
\r
235 /* srp_add_send_descriptor */
\r
237 Puts send descriptor at tail of the sent list
\r
239 @param p_descriptors - pointer to the descriptors structure
\r
240 @param p_descriptor - pointer to the descriptor to add
\r
246 srp_add_send_descriptor(
\r
247 IN srp_descriptors_t *p_descriptors,
\r
248 IN srp_send_descriptor_t *p_descriptor )
\r
250 SRP_ENTER( SRP_DBG_FUNC );
\r
252 cl_spinlock_acquire ( &p_descriptors->sent_list_lock );
\r
254 cl_qlist_insert_tail( &p_descriptors->sent_descriptors, &p_descriptor->list_item );
\r
255 CL_ASSERT( &p_descriptors->sent_descriptors == p_descriptor->list_item.p_list );
\r
257 cl_spinlock_release ( &p_descriptors->sent_list_lock );
\r
259 SRP_EXIT( SRP_DBG_FUNC );
\r
262 /* srp_remove_send_descriptor */
\r
264 Removes send descriptor from the sent list
\r
266 @param p_descriptors - pointer to the descriptors structure
\r
267 @param p_descriptor - pointer to the descriptor to add
\r
273 srp_remove_send_descriptor(
\r
274 IN srp_descriptors_t *p_descriptors,
\r
275 IN srp_send_descriptor_t *p_descriptor )
\r
277 SRP_ENTER( SRP_DBG_FUNC );
\r
279 cl_spinlock_acquire ( &p_descriptors->sent_list_lock );
\r
281 CL_ASSERT( &p_descriptors->sent_descriptors == p_descriptor->list_item.p_list );
\r
282 cl_qlist_remove_item( &p_descriptors->sent_descriptors, &p_descriptor->list_item );
\r
284 cl_spinlock_release ( &p_descriptors->sent_list_lock );
\r
286 SRP_EXIT( SRP_DBG_FUNC );
\r
289 /* srp_remove_lun_head_send_descriptor */
\r
291 Removes and returns the send descriptor from the head of the sent list for the lun specified
\r
293 @param p_descriptors - pointer to the descriptors structure
\r
294 @param lun - lun for which to remove head send descriptor
\r
296 @return - srp_send_descriptor at head of sent list or NULL if empty
\r
298 srp_send_descriptor_t*
\r
299 srp_remove_lun_head_send_descriptor(
\r
300 IN srp_descriptors_t *p_descriptors,
\r
303 srp_send_descriptor_t *p_descriptor;
\r
305 SRP_ENTER( SRP_DBG_FUNC );
\r
307 cl_spinlock_acquire ( &p_descriptors->sent_list_lock );
\r
309 p_descriptor = (srp_send_descriptor_t *)cl_qlist_head( &p_descriptors->sent_descriptors );
\r
310 CL_ASSERT( &p_descriptors->sent_descriptors == p_descriptor->list_item.p_list );
\r
312 while ( p_descriptor != (srp_send_descriptor_t *)cl_qlist_end( &p_descriptors->sent_descriptors ) )
\r
314 if ( p_descriptor->p_srb->Lun == lun )
\r
316 CL_ASSERT( &p_descriptors->sent_descriptors == p_descriptor->list_item.p_list );
\r
317 cl_qlist_remove_item( &p_descriptors->sent_descriptors, &p_descriptor->list_item );
\r
321 p_descriptor = (srp_send_descriptor_t *)cl_qlist_next( &p_descriptor->list_item );
\r
322 CL_ASSERT( &p_descriptors->sent_descriptors == p_descriptor->list_item.p_list );
\r
325 if ( p_descriptor == (srp_send_descriptor_t *)cl_qlist_end( &p_descriptors->sent_descriptors ) )
\r
327 p_descriptor = NULL;
\r
330 cl_spinlock_release ( &p_descriptors->sent_list_lock );
\r
332 SRP_EXIT( SRP_DBG_FUNC );
\r
334 return ( p_descriptor );
\r
337 /* srp_post_send_descriptor */
\r
339 Posts send descriptor across the connection specified and
\r
340 if successful add it to the sent descriptors list
\r
342 @param p_descriptors - pointer to the descriptors structure
\r
343 @param p_descriptor - pointer to the descriptor to send
\r
344 @param p_session - pointer to the session used to send
\r
346 @return - result of post operation, or IB_ERROR if not connected
\r
349 srp_post_send_descriptor(
\r
350 IN srp_descriptors_t *p_descriptors,
\r
351 IN srp_send_descriptor_t *p_descriptor,
\r
352 IN srp_session_t *p_session )
\r
354 ib_api_status_t status = IB_ERROR;
\r
355 srp_connection_t *p_connection;
\r
356 ib_al_ifc_t *p_ifc;
\r
358 SRP_ENTER( SRP_DBG_FUNC );
\r
360 p_connection = &p_session->connection;
\r
361 p_ifc = &p_session->hca.p_hba->ifc;
\r
363 if ( p_connection->state == SRP_CONNECTED )
\r
365 SRP_TRACE( SRP_DBG_VERBOSE, ("wr_id = 0x%"PRIx64".\n", p_descriptor->wr.wr_id) );
\r
366 SRP_TRACE( SRP_DBG_VERBOSE, ("wr_type = 0x%x.\n", p_descriptor->wr.wr_type) );
\r
367 SRP_TRACE( SRP_DBG_VERBOSE, ("send_opt = 0x%x.\n", p_descriptor->wr.send_opt) );
\r
368 SRP_TRACE( SRP_DBG_VERBOSE, ("num_ds = 0x%x.\n", p_descriptor->wr.num_ds) );
\r
370 SRP_TRACE( SRP_DBG_VERBOSE,
\r
371 ("Posting I/O for Function = %s(0x%x), Path = 0x%x, Target = 0x%x, Lun = 0x%x, tag 0x%"PRIx64"\n",
\r
372 g_srb_function_name[p_descriptor->p_srb->Function],
\r
373 p_descriptor->p_srb->Function,
\r
374 p_descriptor->p_srb->PathId,
\r
375 p_descriptor->p_srb->TargetId,
\r
376 p_descriptor->p_srb->Lun,
\r
377 get_srp_command_tag( (srp_cmd_t *)p_descriptor->data_segment )) );
\r
379 if ( get_srp_iu_buffer_type( (srp_iu_buffer_t *)p_descriptor->data_segment ) == SRP_CMD )
\r
381 p_descriptor->ds[0].length = get_srp_command_length( (srp_cmd_t *)p_descriptor->data_segment );
\r
383 else /* task type */
\r
385 p_descriptor->ds[0].length = get_srp_tsk_mgmt_length( (srp_tsk_mgmt_t *)p_descriptor->data_segment );
\r
388 ASSERT( p_descriptor->ds[0].length <= p_connection->init_to_targ_iu_sz );
\r
390 srp_add_send_descriptor( p_descriptors, p_descriptor );
\r
392 status = p_ifc->post_send(
\r
393 p_connection->h_qp, &p_descriptor->wr, NULL );
\r
394 if ( status != IB_SUCCESS )
\r
396 /* Remove From Sent List */
\r
397 srp_remove_send_descriptor( p_descriptors, p_descriptor );
\r
398 SRP_TRACE( SRP_DBG_ERROR,
\r
399 ("Failed to post send descriptor. ib_post_send status = 0x%x tag = 0x%"PRIx64"\n",
\r
401 get_srp_command_tag( (srp_cmd_t *)p_descriptor->data_segment )) );
\r
406 SRP_TRACE( SRP_DBG_ERROR,
\r
407 ("Attempting to post to an unconnected session.\n") );
\r
410 SRP_EXIT( SRP_DBG_FUNC );
\r
415 /* srp_find_matching_send_descriptor */
\r
417 Given a received response find the matching send descriptor
\r
418 which originated the request to the VFx and remove it from
\r
419 the sent descriptor list
\r
421 @param p_descriptors - pointer to the descriptors structure
\r
422 @param tag - tag of descriptor to find
\r
424 @return - pointer to send descriptor or NULL if not found
\r
426 srp_send_descriptor_t*
\r
427 srp_find_matching_send_descriptor(
\r
428 IN srp_descriptors_t *p_descriptors,
\r
431 srp_send_descriptor_t *p_send_descriptor;
\r
433 SRP_ENTER( SRP_DBG_FUNC );
\r
435 cl_spinlock_acquire( &p_descriptors->sent_list_lock );
\r
437 p_send_descriptor = (srp_send_descriptor_t *)cl_qlist_head( &p_descriptors->sent_descriptors );
\r
438 CL_ASSERT( &p_descriptors->sent_descriptors == p_send_descriptor->list_item.p_list );
\r
440 SRP_TRACE( SRP_DBG_VERBOSE, ("rsp tag = 0x%"PRIx64".\n", tag) );
\r
442 while ( p_send_descriptor != (srp_send_descriptor_t *)cl_qlist_end( &p_descriptors->sent_descriptors ) )
\r
444 SRP_TRACE( SRP_DBG_VERBOSE, ("cmd tag = 0x%"PRIx64".\n",
\r
445 get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment )) );
\r
447 if ( get_srp_command_tag( (srp_cmd_t *)p_send_descriptor->data_segment ) == tag )
\r
449 CL_ASSERT( &p_descriptors->sent_descriptors == p_send_descriptor->list_item.p_list );
\r
450 cl_qlist_remove_item( &p_descriptors->sent_descriptors, &p_send_descriptor->list_item );
\r
454 p_send_descriptor = (srp_send_descriptor_t *)cl_qlist_next( &p_send_descriptor->list_item );
\r
457 /* This is not an error. The request may have been aborted */
\r
458 p_send_descriptor = NULL;
\r
461 cl_spinlock_release( &p_descriptors->sent_list_lock );
\r
463 SRP_EXIT( SRP_DBG_FUNC );
\r
465 return ( p_send_descriptor );
\r
468 /* srp_build_send_descriptor */
\r
470 Initializes a send descriptor's fields
\r
472 @param p_dev_ext - our context pointer
\r
473 @param p_srb - scsi request to send to target
\r
474 @param p_srp_conn_info - information about our connection to the VFx
\r
479 srp_build_send_descriptor(
\r
480 IN PVOID p_dev_ext,
\r
481 IN OUT PSCSI_REQUEST_BLOCK p_srb,
\r
482 IN p_srp_conn_info_t p_srp_conn_info )
\r
484 srp_send_descriptor_t *p_send_descriptor = (srp_send_descriptor_t *)p_srb->SrbExtension;
\r
485 STOR_PHYSICAL_ADDRESS physical_address;
\r
488 SRP_ENTER( SRP_DBG_FUNC );
\r
490 cl_memclr( p_send_descriptor, (sizeof ( srp_send_descriptor_t ) - SRP_MAX_IU_SIZE) );
\r
492 physical_address = StorPortGetPhysicalAddress( p_dev_ext, p_srb, p_send_descriptor->data_segment, &length );
\r
494 p_send_descriptor->wr.wr_id = (uint64_t)((uintn_t)p_send_descriptor);
\r
495 p_send_descriptor->wr.wr_type = WR_SEND;
\r
496 p_send_descriptor->wr.send_opt = (p_srp_conn_info->signal_send_completion == TRUE) ? IB_SEND_OPT_SIGNALED : 0;
\r
497 p_send_descriptor->wr.num_ds = 1;
\r
498 p_send_descriptor->wr.ds_array = p_send_descriptor->ds;
\r
499 p_send_descriptor->tag = p_srp_conn_info->tag;
\r
500 p_send_descriptor->p_srb = p_srb;
\r
501 p_send_descriptor->ds[0].vaddr = p_srp_conn_info->vaddr + physical_address.QuadPart;
\r
502 p_send_descriptor->ds[0].length = p_srp_conn_info->init_to_targ_iu_sz;
\r
503 p_send_descriptor->ds[0].lkey = p_srp_conn_info->lkey;
\r
505 SRP_TRACE( SRP_DBG_VERBOSE, ("hca vaddr = 0x%"PRIx64".\n", p_srp_conn_info->vaddr));
\r
506 SRP_TRACE( SRP_DBG_VERBOSE, ("physical_address = 0x%"PRIx64".\n", physical_address.QuadPart));
\r
507 SRP_TRACE( SRP_DBG_VERBOSE, ("IU vaddr = 0x%"PRIx64".\n", p_send_descriptor->ds[0].vaddr));
\r
508 SRP_TRACE( SRP_DBG_VERBOSE, ("length = %d.\n", p_send_descriptor->ds[0].length));
\r
509 SRP_TRACE( SRP_DBG_VERBOSE, ("lkey = 0x%x.\n", p_send_descriptor->ds[0].lkey));
\r
511 SRP_EXIT( SRP_DBG_FUNC );
\r