iPXE
srp.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31FILE_LICENCE ( BSD2 );
32
33#include <stdlib.h>
34#include <string.h>
35#include <errno.h>
36#include <ipxe/scsi.h>
37#include <ipxe/xfer.h>
38#include <ipxe/features.h>
39#include <ipxe/srp.h>
40
41/**
42 * @file
43 *
44 * SCSI RDMA Protocol
45 *
46 */
47
49
50/** Maximum length of any initiator-to-target IU that we will send
51 *
52 * The longest IU is a SRP_CMD with no additional CDB and two direct
53 * data buffer descriptors, which comes to 80 bytes.
54 */
55#define SRP_MAX_I_T_IU_LEN 80
56
57/* Error numbers generated by SRP login rejection */
58#define EINFO_SRP_LOGIN_REJ( reason, desc ) \
59 __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )
60#define EPERM_UNKNOWN \
61 __einfo_error ( EINFO_EPERM_UNKNOWN )
62#define EINFO_EPERM_UNKNOWN EINFO_SRP_LOGIN_REJ ( \
63 SRP_LOGIN_REJ_REASON_UNKNOWN, \
64 "Unable to establish RDMA channel, no reason specified" )
65#define EPERM_INSUFFICIENT_RESOURCES \
66 __einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES )
67#define EINFO_EPERM_INSUFFICIENT_RESOURCES EINFO_SRP_LOGIN_REJ ( \
68 SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES, \
69 "Insufficient RDMA channel resources" )
70#define EPERM_BAD_MAX_I_T_IU_LEN \
71 __einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN )
72#define EINFO_EPERM_BAD_MAX_I_T_IU_LEN EINFO_SRP_LOGIN_REJ ( \
73 SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN, \
74 "Requested maximum initiator to target IU length value too large" )
75#define EPERM_CANNOT_ASSOCIATE \
76 __einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE )
77#define EINFO_EPERM_CANNOT_ASSOCIATE EINFO_SRP_LOGIN_REJ ( \
78 SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE, \
79 "Unable to associate RDMA channel with specified I_T nexus" )
80#define EPERM_UNSUPPORTED_BUFFER_FORMAT \
81 __einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT )
82#define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT EINFO_SRP_LOGIN_REJ ( \
83 SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT, \
84 "One or more requested data buffer descriptor formats not supported" )
85#define EPERM_NO_MULTIPLE_CHANNELS \
86 __einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS )
87#define EINFO_EPERM_NO_MULTIPLE_CHANNELS EINFO_SRP_LOGIN_REJ ( \
88 SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS, \
89 "SRP target does not support multiple RDMA channels per I_T nexus" )
90#define EPERM_NO_MORE_CHANNELS \
91 __einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS )
92#define EINFO_EPERM_NO_MORE_CHANNELS EINFO_SRP_LOGIN_REJ ( \
93 SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS, \
94 "RDMA channel limit reached for this initiator" )
95#define EPERM_LOGIN_REJ( reason_nibble ) \
96 EUNIQ ( EINFO_EPERM, (reason_nibble), EPERM_UNKNOWN, \
97 EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN, \
98 EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT, \
99 EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS )
100
101/** An SRP device */
103 /** Reference count */
105
106 /** SCSI command issuing interface */
108 /** Underlying data transfer interface */
110
111 /** RDMA memory handle */
113 /** Login completed successfully */
115
116 /** List of active commands */
118};
119
120/** An SRP command */
122 /** Reference count */
124 /** SRP device */
126 /** List of active commands */
128
129 /** SCSI command interface */
131 /** Command tag */
133};
134
135/**
136 * Get reference to SRP device
137 *
138 * @v srpdev SRP device
139 * @ret srpdev SRP device
140 */
141static inline __attribute__ (( always_inline )) struct srp_device *
142srpdev_get ( struct srp_device *srpdev ) {
143 ref_get ( &srpdev->refcnt );
144 return srpdev;
145}
146
147/**
148 * Drop reference to SRP device
149 *
150 * @v srpdev SRP device
151 */
152static inline __attribute__ (( always_inline )) void
153srpdev_put ( struct srp_device *srpdev ) {
154 ref_put ( &srpdev->refcnt );
155}
156
157/**
158 * Get reference to SRP command
159 *
160 * @v srpcmd SRP command
161 * @ret srpcmd SRP command
162 */
163static inline __attribute__ (( always_inline )) struct srp_command *
164srpcmd_get ( struct srp_command *srpcmd ) {
165 ref_get ( &srpcmd->refcnt );
166 return srpcmd;
167}
168
169/**
170 * Drop reference to SRP command
171 *
172 * @v srpcmd SRP command
173 */
174static inline __attribute__ (( always_inline )) void
175srpcmd_put ( struct srp_command *srpcmd ) {
176 ref_put ( &srpcmd->refcnt );
177}
178
179/**
180 * Free SRP command
181 *
182 * @v refcnt Reference count
183 */
184static void srpcmd_free ( struct refcnt *refcnt ) {
185 struct srp_command *srpcmd =
187
188 assert ( list_empty ( &srpcmd->list ) );
189
190 srpdev_put ( srpcmd->srpdev );
191 free ( srpcmd );
192}
193
194/**
195 * Close SRP command
196 *
197 * @v srpcmd SRP command
198 * @v rc Reason for close
199 */
200static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
201 struct srp_device *srpdev = srpcmd->srpdev;
202
203 if ( rc != 0 ) {
204 DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
205 srpdev, srpcmd->tag, strerror ( rc ) );
206 }
207
208 /* Remove from list of commands */
209 if ( ! list_empty ( &srpcmd->list ) ) {
210 list_del ( &srpcmd->list );
211 INIT_LIST_HEAD ( &srpcmd->list );
212 srpcmd_put ( srpcmd );
213 }
214
215 /* Shut down interfaces */
216 intf_shutdown ( &srpcmd->scsi, rc );
217}
218
219/**
220 * Close SRP device
221 *
222 * @v srpdev SRP device
223 * @v rc Reason for close
224 */
225static void srpdev_close ( struct srp_device *srpdev, int rc ) {
226 struct srp_command *srpcmd;
227 struct srp_command *tmp;
228
229 if ( rc != 0 ) {
230 DBGC ( srpdev, "SRP %p closed: %s\n",
231 srpdev, strerror ( rc ) );
232 }
233
234 /* Shut down interfaces */
237
238 /* Shut down any active commands */
240 srpcmd_get ( srpcmd );
241 srpcmd_close ( srpcmd, rc );
242 srpcmd_put ( srpcmd );
243 }
244}
245
246/**
247 * Identify SRP command by tag
248 *
249 * @v srpdev SRP device
250 * @v tag Command tag
251 * @ret srpcmd SRP command, or NULL
252 */
253static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
254 uint32_t tag ) {
255 struct srp_command *srpcmd;
256
257 list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
258 if ( srpcmd->tag == tag )
259 return srpcmd;
260 }
261 return NULL;
262}
263
264/**
265 * Choose an SRP command tag
266 *
267 * @v srpdev SRP device
268 * @ret tag New tag, or negative error
269 */
270static int srp_new_tag ( struct srp_device *srpdev ) {
271 static uint16_t tag_idx;
272 unsigned int i;
273
274 for ( i = 0 ; i < 65536 ; i++ ) {
275 tag_idx++;
276 if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
277 return tag_idx;
278 }
279 return -EADDRINUSE;
280}
281
282/**
283 * Transmit SRP login request
284 *
285 * @v srpdev SRP device
286 * @v initiator Initiator port ID
287 * @v target Target port ID
288 * @v tag Command tag
289 * @ret rc Return status code
290 */
291static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
292 union srp_port_id *target, uint32_t tag ) {
293 struct io_buffer *iobuf;
294 struct srp_login_req *login_req;
295 int rc;
296
297 /* Allocate I/O buffer */
298 iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
299 if ( ! iobuf )
300 return -ENOMEM;
301
302 /* Construct login request IU */
303 login_req = iob_put ( iobuf, sizeof ( *login_req ) );
304 memset ( login_req, 0, sizeof ( *login_req ) );
305 login_req->type = SRP_LOGIN_REQ;
306 login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
307 login_req->tag.dwords[1] = htonl ( tag );
308 login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
310 memcpy ( &login_req->initiator, initiator,
311 sizeof ( login_req->initiator ) );
312 memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
313
314 DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
315 DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
316
317 /* Send login request IU */
318 if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
319 DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
320 "%s\n", srpdev, tag, strerror ( rc ) );
321 return rc;
322 }
323
324 return 0;
325}
326
327/**
328 * Receive SRP login response
329 *
330 * @v srpdev SRP device
331 * @v data SRP IU
332 * @v len Length of SRP IU
333 * @ret rc Return status code
334 */
335static int srp_login_rsp ( struct srp_device *srpdev,
336 const void *data, size_t len ) {
337 const struct srp_login_rsp *login_rsp = data;
338
339 /* Sanity check */
340 if ( len < sizeof ( *login_rsp ) ) {
341 DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
342 srpdev, len );
343 return -EINVAL;
344 }
345 DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
346 srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
347 DBGC_HDA ( srpdev, 0, data, len );
348
349 /* Mark as logged in */
350 srpdev->logged_in = 1;
351 DBGC ( srpdev, "SRP %p logged in\n", srpdev );
352
353 /* Notify of window change */
354 xfer_window_changed ( &srpdev->scsi );
355
356 return 0;
357}
358
359/**
360 * Receive SRP login rejection
361 *
362 * @v srpdev SRP device
363 * @v data SRP IU
364 * @v len Length of SRP IU
365 * @ret rc Return status code
366 */
367static int srp_login_rej ( struct srp_device *srpdev,
368 const void *data, size_t len ) {
369 const struct srp_login_rej *login_rej = data;
371
372 /* Sanity check */
373 if ( len < sizeof ( *login_rej ) ) {
374 DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
375 srpdev, len );
376 return -EINVAL;
377 }
378 reason = ntohl ( login_rej->reason );
379 DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
380 srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
381 DBGC_HDA ( srpdev, 0, data, len );
382
383 /* Login rejection always indicates an error */
385 -EPERM_LOGIN_REJ ( reason ) : -EACCES );
386}
387
388/**
389 * Transmit SRP SCSI command
390 *
391 * @v srpdev SRP device
392 * @v command SCSI command
393 * @v tag Command tag
394 * @ret rc Return status code
395 */
396static int srp_cmd ( struct srp_device *srpdev,
397 struct scsi_cmd *command,
398 uint32_t tag ) {
399 struct io_buffer *iobuf;
400 struct srp_cmd *cmd;
401 struct srp_memory_descriptor *data_out;
402 struct srp_memory_descriptor *data_in;
403 int rc;
404
405 /* Sanity check */
406 if ( ! srpdev->logged_in ) {
407 DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
408 "login completes\n", srpdev, tag );
409 return -EBUSY;
410 }
411
412 /* Allocate I/O buffer */
413 iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
414 if ( ! iobuf )
415 return -ENOMEM;
416
417 /* Construct base portion */
418 cmd = iob_put ( iobuf, sizeof ( *cmd ) );
419 memset ( cmd, 0, sizeof ( *cmd ) );
420 cmd->type = SRP_CMD;
421 cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
422 cmd->tag.dwords[1] = htonl ( tag );
423 memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
424 memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
425
426 /* Construct data-out descriptor, if present */
427 if ( command->data_out ) {
428 cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
429 data_out = iob_put ( iobuf, sizeof ( *data_out ) );
430 data_out->address =
431 cpu_to_be64 ( virt_to_phys ( command->data_out ) );
432 data_out->handle = ntohl ( srpdev->memory_handle );
433 data_out->len = ntohl ( command->data_out_len );
434 }
435
436 /* Construct data-in descriptor, if present */
437 if ( command->data_in ) {
438 cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
439 data_in = iob_put ( iobuf, sizeof ( *data_in ) );
440 data_in->address =
441 cpu_to_be64 ( virt_to_phys ( command->data_in ) );
442 data_in->handle = ntohl ( srpdev->memory_handle );
443 data_in->len = ntohl ( command->data_in_len );
444 }
445
446 DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
447 srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
448
449 /* Send IU */
450 if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
451 DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
452 srpdev, tag, strerror ( rc ) );
453 return rc;
454 }
455
456 return 0;
457}
458
459/**
460 * Receive SRP SCSI response
461 *
462 * @v srpdev SRP device
463 * @v data SRP IU
464 * @v len Length of SRP IU
465 * @ret rc Returns status code
466 */
467static int srp_rsp ( struct srp_device *srpdev,
468 const void *data, size_t len ) {
469 const struct srp_rsp *rsp = data;
470 struct srp_command *srpcmd;
471 struct scsi_rsp response;
472 ssize_t data_out_residual_count;
473 ssize_t data_in_residual_count;
474
475 /* Sanity check */
476 if ( ( len < sizeof ( *rsp ) ) ||
477 ( len < ( sizeof ( *rsp ) +
479 srp_rsp_sense_data_len ( rsp ) ) ) ) {
480 DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
481 srpdev, len );
482 return -EINVAL;
483 }
484 DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
485 "%08x valid %02x%s%s%s%s%s%s\n",
486 srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
487 ntohl ( rsp->data_out_residual_count ),
488 ntohl ( rsp->data_in_residual_count ), rsp->valid,
489 ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
490 ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
491 ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
492 ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
493 ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
494 ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
495
496 /* Identify command by tag */
497 srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
498 if ( ! srpcmd ) {
499 DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
500 srpdev, ntohl ( rsp->tag.dwords[1] ) );
501 return -ENOENT;
502 }
503
504 /* Hold command reference for remainder of function */
505 srpcmd_get ( srpcmd );
506
507 /* Build SCSI response */
508 memset ( &response, 0, sizeof ( response ) );
509 response.status = rsp->status;
510 data_out_residual_count = ntohl ( rsp->data_out_residual_count );
511 data_in_residual_count = ntohl ( rsp->data_in_residual_count );
512 if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
513 response.overrun = data_out_residual_count;
514 } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
515 response.overrun = -(data_out_residual_count);
516 } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
517 response.overrun = data_in_residual_count;
518 } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
519 response.overrun = -(data_in_residual_count);
520 }
522 srp_rsp_sense_data_len ( rsp ), &response.sense );
523
524 /* Report SCSI response */
525 scsi_response ( &srpcmd->scsi, &response );
526
527 /* Close SCSI command */
528 srpcmd_close ( srpcmd, 0 );
529
530 /* Drop temporary command reference */
531 srpcmd_put ( srpcmd );
532
533 return 0;
534}
535
536/**
537 * Receive SRP unrecognised response IU
538 *
539 * @v srpdev SRP device
540 * @v data SRP IU
541 * @v len Length of SRP IU
542 * @ret rc Returns status code
543 */
544static int srp_unrecognised ( struct srp_device *srpdev,
545 const void *data, size_t len ) {
546 const struct srp_common *common = data;
547
548 DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
549 srpdev, ntohl ( common->tag.dwords[1] ), common->type );
550 DBGC_HDA ( srpdev, 0, data, len );
551
552 return -ENOTSUP;
553}
554
555/** SRP command SCSI interface operations */
558};
559
560/** SRP command SCSI interface descriptor */
562 INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
563
564/**
565 * Issue SRP SCSI command
566 *
567 * @v srpdev SRP device
568 * @v parent Parent interface
569 * @v command SCSI command
570 * @ret tag Command tag, or negative error
571 */
572static int srpdev_scsi_command ( struct srp_device *srpdev,
573 struct interface *parent,
574 struct scsi_cmd *command ) {
575 struct srp_command *srpcmd;
576 int tag;
577 int rc;
578
579 /* Allocate command tag */
580 tag = srp_new_tag ( srpdev );
581 if ( tag < 0 ) {
582 rc = tag;
583 goto err_tag;
584 }
585
586 /* Allocate and initialise structure */
587 srpcmd = zalloc ( sizeof ( *srpcmd ) );
588 if ( ! srpcmd ) {
589 rc = -ENOMEM;
590 goto err_zalloc;
591 }
592 ref_init ( &srpcmd->refcnt, srpcmd_free );
593 intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
594 srpcmd->srpdev = srpdev_get ( srpdev );
595 list_add ( &srpcmd->list, &srpdev->commands );
596 srpcmd->tag = tag;
597
598 /* Send command IU */
599 if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
600 goto err_cmd;
601
602 /* Attach to parent interface, leave reference with command
603 * list, and return.
604 */
605 intf_plug_plug ( &srpcmd->scsi, parent );
606 return srpcmd->tag;
607
608 err_cmd:
609 srpcmd_close ( srpcmd, rc );
610 err_zalloc:
611 err_tag:
612 return rc;
613}
614
615/**
616 * Receive data from SRP socket
617 *
618 * @v srpdev SRP device
619 * @v iobuf Datagram I/O buffer
620 * @v meta Data transfer metadata
621 * @ret rc Return status code
622 */
623static int srpdev_deliver ( struct srp_device *srpdev,
624 struct io_buffer *iobuf,
625 struct xfer_metadata *meta __unused ) {
626 struct srp_common *common = iobuf->data;
627 int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
628 int rc;
629
630 /* Sanity check */
631 if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
632 DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
633 srpdev, iob_len ( iobuf ) );
634 rc = -EINVAL;
635 goto err;
636 }
637
638 /* Determine IU type */
639 switch ( common->type ) {
640 case SRP_LOGIN_RSP:
642 break;
643 case SRP_LOGIN_REJ:
645 break;
646 case SRP_RSP:
647 type = srp_rsp;
648 break;
649 default:
651 break;
652 }
653
654 /* Handle IU */
655 if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
656 goto err;
657
658 free_iob ( iobuf );
659 return 0;
660
661 err:
662 DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
663 srpdev, strerror ( rc ) );
664 DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
665 free_iob ( iobuf );
666 srpdev_close ( srpdev, rc );
667 return rc;
668}
669
670/**
671 * Check SRP device flow-control window
672 *
673 * @v srpdev SRP device
674 * @ret len Length of window
675 */
676static size_t srpdev_window ( struct srp_device *srpdev ) {
677 return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
678}
679
680/** SRP device socket interface operations */
685
686/** SRP device socket interface descriptor */
689 scsi );
690
691/** SRP device SCSI interface operations */
697
698/** SRP device SCSI interface descriptor */
700 INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket );
701
702/**
703 * Open SRP device
704 *
705 * @v block Block control interface
706 * @v socket Socket interface
707 * @v initiator Initiator port ID
708 * @v target Target port ID
709 * @v memory_handle RDMA memory handle
710 * @v lun SCSI LUN
711 * @ret rc Return status code
712 */
713int srp_open ( struct interface *block, struct interface *socket,
714 union srp_port_id *initiator, union srp_port_id *target,
715 uint32_t memory_handle, struct scsi_lun *lun ) {
716 struct srp_device *srpdev;
717 int tag;
718 int rc;
719
720 /* Allocate and initialise structure */
721 srpdev = zalloc ( sizeof ( *srpdev ) );
722 if ( ! srpdev ) {
723 rc = -ENOMEM;
724 goto err_zalloc;
725 }
726 ref_init ( &srpdev->refcnt, NULL );
727 intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
728 intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
729 INIT_LIST_HEAD ( &srpdev->commands );
731 DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
732 ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
733 ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
734 ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
735 ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
736
737 /* Attach to socket interface and initiate login */
738 intf_plug_plug ( &srpdev->socket, socket );
739 tag = srp_new_tag ( srpdev );
740 assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
741 if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
742 goto err_login;
743
744 /* Attach SCSI device to parent interface */
745 if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
746 DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
747 srpdev, strerror ( rc ) );
748 goto err_scsi_open;
749 }
750
751 /* Mortalise self and return */
752 ref_put ( &srpdev->refcnt );
753 return 0;
754
755 err_scsi_open:
756 err_login:
757 srpdev_close ( srpdev, rc );
758 ref_put ( &srpdev->refcnt );
759 err_zalloc:
760 return rc;
761}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct golan_eqe_cmd cmd
Definition CIB_PRM.h:1
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned short uint16_t
Definition stdint.h:11
unsigned int uint32_t
Definition stdint.h:12
signed long ssize_t
Definition stdint.h:7
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
ring len
Length.
Definition dwmac.h:226
uint64_t tag
Identity tag.
Definition edd.h:1
uint8_t lun
Logical Unit Number.
Definition edd.h:3
uint32_t type
Operating system type.
Definition ena.h:1
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define DHCP_EB_FEATURE_SRP
SRP protocol.
Definition features.h:48
#define FEATURE_PROTOCOL
Network protocols.
Definition features.h:22
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
#define EINVAL
Invalid argument.
Definition errno.h:429
#define EADDRINUSE
Address already in use.
Definition errno.h:304
#define ENOMEM
Not enough space.
Definition errno.h:535
#define EBUSY
Device or resource busy.
Definition errno.h:339
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define EACCES
Permission denied.
Definition errno.h:299
#define SCSI_CDB_DATA(cdb)
printf() parameters for dumping a scsi_cdb
Definition scsi.h:223
#define SCSI_CDB_FORMAT
printf() format for dumping a scsi_cdb
Definition scsi.h:219
struct ib_cm_common common
Definition ib_mad.h:0
uint16_t reason
Rejection reason.
Definition ib_mad.h:9
#define ntohl(value)
Definition byteswap.h:135
#define htonl(value)
Definition byteswap.h:134
#define cpu_to_be64(value)
Definition byteswap.h:112
#define __attribute__(x)
Definition compiler.h:10
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
#define INTF_DESC_PASSTHRU(object_type, intf, operations, passthru)
Define an object interface descriptor with pass-through interface.
Definition interface.h:98
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
#define iob_put(iobuf, len)
Definition iobuf.h:125
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
Feature list.
#define FEATURE(category, text, feature_opt, version)
Declare a feature.
Definition features.h:101
uint64_t rsp
Definition librm.h:18
unsigned long tmp
Definition linux_pci.h:65
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition list.h:459
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition list.h:46
#define list_empty(list)
Test whether a list is empty.
Definition list.h:137
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
uint8_t block[3][8]
DES-encrypted blocks.
Definition mschapv2.h:1
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define ref_get(refcnt)
Get additional reference to object.
Definition refcnt.h:93
#define ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
int scsi_open(struct interface *block, struct interface *scsi, struct scsi_lun *lun)
Open SCSI device.
Definition scsi.c:985
void scsi_response(struct interface *intf, struct scsi_rsp *response)
Report SCSI response.
Definition scsi.c:207
void scsi_parse_sense(const void *data, size_t len, struct scsi_sns_descriptor *sense)
Parse SCSI sense data.
Definition scsi.c:147
SCSI devices.
static struct interface_descriptor srpdev_scsi_desc
SRP device SCSI interface descriptor.
Definition srp.c:699
static int srp_cmd(struct srp_device *srpdev, struct scsi_cmd *command, uint32_t tag)
Transmit SRP SCSI command.
Definition srp.c:396
static struct srp_device * srpdev_get(struct srp_device *srpdev)
Get reference to SRP device.
Definition srp.c:142
static struct srp_command * srpcmd_get(struct srp_command *srpcmd)
Get reference to SRP command.
Definition srp.c:164
static int srp_login(struct srp_device *srpdev, union srp_port_id *initiator, union srp_port_id *target, uint32_t tag)
Transmit SRP login request.
Definition srp.c:291
static struct srp_command * srp_find_tag(struct srp_device *srpdev, uint32_t tag)
Identify SRP command by tag.
Definition srp.c:253
static struct interface_operation srpdev_scsi_op[]
SRP device SCSI interface operations.
Definition srp.c:692
static int srp_login_rej(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP login rejection.
Definition srp.c:367
static int srpdev_deliver(struct srp_device *srpdev, struct io_buffer *iobuf, struct xfer_metadata *meta __unused)
Receive data from SRP socket.
Definition srp.c:623
#define SRP_MAX_I_T_IU_LEN
Maximum length of any initiator-to-target IU that we will send.
Definition srp.c:55
static void srpcmd_free(struct refcnt *refcnt)
Free SRP command.
Definition srp.c:184
static size_t srpdev_window(struct srp_device *srpdev)
Check SRP device flow-control window.
Definition srp.c:676
static int srp_login_rsp(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP login response.
Definition srp.c:335
static int srp_unrecognised(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP unrecognised response IU.
Definition srp.c:544
static void srpdev_put(struct srp_device *srpdev)
Drop reference to SRP device.
Definition srp.c:153
static struct interface_operation srpcmd_scsi_op[]
SRP command SCSI interface operations.
Definition srp.c:556
static struct interface_descriptor srpdev_socket_desc
SRP device socket interface descriptor.
Definition srp.c:687
static void srpcmd_close(struct srp_command *srpcmd, int rc)
Close SRP command.
Definition srp.c:200
static void srpcmd_put(struct srp_command *srpcmd)
Drop reference to SRP command.
Definition srp.c:175
static void srpdev_close(struct srp_device *srpdev, int rc)
Close SRP device.
Definition srp.c:225
#define EPERM_LOGIN_REJ(reason_nibble)
Definition srp.c:95
static struct interface_operation srpdev_socket_op[]
SRP device socket interface operations.
Definition srp.c:681
static int srp_rsp(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP SCSI response.
Definition srp.c:467
int srp_open(struct interface *block, struct interface *socket, union srp_port_id *initiator, union srp_port_id *target, uint32_t memory_handle, struct scsi_lun *lun)
Open SRP device.
Definition srp.c:713
static int srpdev_scsi_command(struct srp_device *srpdev, struct interface *parent, struct scsi_cmd *command)
Issue SRP SCSI command.
Definition srp.c:572
static int srp_new_tag(struct srp_device *srpdev)
Choose an SRP command tag.
Definition srp.c:270
static struct interface_descriptor srpcmd_scsi_desc
SRP command SCSI interface descriptor.
Definition srp.c:561
SCSI RDMA Protocol.
#define SRP_LOGIN_REQ
Type of an SRP login request.
Definition srp.h:96
#define SRP_LOGIN_REJ
Type of an SRP login rejection.
Definition srp.h:223
#define SRP_TAG_MAGIC
SRP tag magic marker.
Definition srp.h:34
#define SRP_LOGIN_REJ_REASON_DEFINED(reason)
SRP login rejection reason is defined.
Definition srp.h:247
#define SRP_RSP_VALID_DOOVER
Data-out residual count field is valid and represents an overflow.
Definition srp.h:574
#define SRP_RSP_VALID_SNSVALID
Sense data list length field is valid.
Definition srp.h:577
static const void * srp_rsp_sense_data(const struct srp_rsp *rsp)
Get sense data portion of SCSI response.
Definition srp.h:610
#define SRP_RSP
Type of an SRP SCSI response.
Definition srp.h:559
#define SRP_RSP_VALID_DOUNDER
Data-out residual count field is valid and represents an underflow.
Definition srp.h:571
#define SRP_RSP_VALID_RSPVALID
Response data list length field is valid.
Definition srp.h:580
#define SRP_RSP_VALID_DIOVER
Data-in residual count field is valid and represents an overflow.
Definition srp.h:568
#define SRP_LOGIN_REQ_FMT_DDBD
Require direct data buffer descriptor format.
Definition srp.h:102
static size_t srp_rsp_response_data_len(const struct srp_rsp *rsp)
Get length of response data portion of SCSI response.
Definition srp.h:599
#define SRP_CMD
Type of an SRP SCSI command.
Definition srp.h:461
#define SRP_CMD_DI_FMT_DIRECT
Direct data-in buffer format.
Definition srp.h:482
#define SRP_RSP_VALID_DIUNDER
Data-in residual count field is valid and represents an underflow.
Definition srp.h:565
#define SRP_CMD_DO_FMT_DIRECT
Direct data-out buffer format.
Definition srp.h:473
#define SRP_LOGIN_RSP
Type of an SRP login response.
Definition srp.h:164
static size_t srp_rsp_sense_data_len(const struct srp_rsp *rsp)
Get length of sense data portion of SCSI response.
Definition srp.h:622
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
A command-line command.
Definition command.h:10
An object interface descriptor.
Definition interface.h:56
An object interface operation.
Definition interface.h:18
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
A doubly-linked list entry (or list head)
Definition list.h:19
A reference counter.
Definition refcnt.h:27
A SCSI command information unit.
Definition scsi.h:249
A SCSI command.
Definition scsi.c:263
A SCSI LUN.
Definition scsi.h:236
A SCSI response information unit.
Definition scsi.h:322
struct scsi_sns_descriptor sense
Autosense data (if any)
Definition scsi.h:333
uint8_t status
SCSI status code.
Definition scsi.h:324
ssize_t overrun
Data overrun (or negative underrun)
Definition scsi.h:326
An SRP SCSI command.
Definition srp.h:415
An SRP command.
Definition srp.c:121
struct list_head list
List of active commands.
Definition srp.c:127
struct refcnt refcnt
Reference count.
Definition srp.c:123
struct srp_device * srpdev
SRP device.
Definition srp.c:125
struct interface scsi
SCSI command interface.
Definition srp.c:130
uint32_t tag
Command tag.
Definition srp.c:132
SRP information unit common fields.
Definition srp.h:43
An SRP device.
Definition srp.c:102
uint32_t memory_handle
RDMA memory handle.
Definition srp.c:112
struct interface socket
Underlying data transfer interface.
Definition srp.c:109
int logged_in
Login completed successfully.
Definition srp.c:114
struct refcnt refcnt
Reference count.
Definition srp.c:104
struct interface scsi
SCSI command issuing interface.
Definition srp.c:107
struct list_head commands
List of active commands.
Definition srp.c:117
An SRP login rejection.
Definition srp.h:195
uint32_t reason
Reason.
Definition srp.h:207
union srp_tag tag
Tag.
Definition srp.h:209
An SRP login request information unit.
Definition srp.h:60
union srp_port_id target
Target port identifier.
Definition srp.h:92
uint16_t required_buffer_formats
Required buffer formats.
Definition srp.h:79
union srp_port_id initiator
Initiator port identifier.
Definition srp.h:90
uint8_t type
Information unit type.
Definition srp.h:65
uint32_t max_i_t_iu_len
Requested maximum initiator to target IU length.
Definition srp.h:71
union srp_tag tag
Tag.
Definition srp.h:69
An SRP login response.
Definition srp.h:130
union srp_tag tag
Tag.
Definition srp.h:141
An SRP memory descriptor.
Definition srp.h:500
uint64_t address
Virtual address.
Definition srp.h:502
uint32_t handle
Memory handle.
Definition srp.h:504
uint32_t len
Data length.
Definition srp.h:506
An SRP SCSI response.
Definition srp.h:517
Data transfer metadata.
Definition xfer.h:23
An SRP port ID.
Definition srp.h:37
uint32_t dwords[4]
Definition srp.h:39
uint32_t dwords[2]
Definition srp.h:30
size_t xfer_window(struct interface *intf)
Check flow control window.
Definition xfer.c:117
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition xfer.c:159
void xfer_window_changed(struct interface *intf)
Report change of flow control window.
Definition xfer.c:147
int xfer_deliver_iob(struct interface *intf, struct io_buffer *iobuf)
Deliver datagram as I/O buffer without metadata.
Definition xfer.c:256
Data transfer interfaces.