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 );
32FILE_SECBOOT ( FORBIDDEN );
33
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
37#include <ipxe/scsi.h>
38#include <ipxe/xfer.h>
39#include <ipxe/features.h>
40#include <ipxe/srp.h>
41
42/**
43 * @file
44 *
45 * SCSI RDMA Protocol
46 *
47 */
48
50
51/** Maximum length of any initiator-to-target IU that we will send
52 *
53 * The longest IU is a SRP_CMD with no additional CDB and two direct
54 * data buffer descriptors, which comes to 80 bytes.
55 */
56#define SRP_MAX_I_T_IU_LEN 80
57
58/* Error numbers generated by SRP login rejection */
59#define EINFO_SRP_LOGIN_REJ( reason, desc ) \
60 __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )
61#define EPERM_UNKNOWN \
62 __einfo_error ( EINFO_EPERM_UNKNOWN )
63#define EINFO_EPERM_UNKNOWN EINFO_SRP_LOGIN_REJ ( \
64 SRP_LOGIN_REJ_REASON_UNKNOWN, \
65 "Unable to establish RDMA channel, no reason specified" )
66#define EPERM_INSUFFICIENT_RESOURCES \
67 __einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES )
68#define EINFO_EPERM_INSUFFICIENT_RESOURCES EINFO_SRP_LOGIN_REJ ( \
69 SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES, \
70 "Insufficient RDMA channel resources" )
71#define EPERM_BAD_MAX_I_T_IU_LEN \
72 __einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN )
73#define EINFO_EPERM_BAD_MAX_I_T_IU_LEN EINFO_SRP_LOGIN_REJ ( \
74 SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN, \
75 "Requested maximum initiator to target IU length value too large" )
76#define EPERM_CANNOT_ASSOCIATE \
77 __einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE )
78#define EINFO_EPERM_CANNOT_ASSOCIATE EINFO_SRP_LOGIN_REJ ( \
79 SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE, \
80 "Unable to associate RDMA channel with specified I_T nexus" )
81#define EPERM_UNSUPPORTED_BUFFER_FORMAT \
82 __einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT )
83#define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT EINFO_SRP_LOGIN_REJ ( \
84 SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT, \
85 "One or more requested data buffer descriptor formats not supported" )
86#define EPERM_NO_MULTIPLE_CHANNELS \
87 __einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS )
88#define EINFO_EPERM_NO_MULTIPLE_CHANNELS EINFO_SRP_LOGIN_REJ ( \
89 SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS, \
90 "SRP target does not support multiple RDMA channels per I_T nexus" )
91#define EPERM_NO_MORE_CHANNELS \
92 __einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS )
93#define EINFO_EPERM_NO_MORE_CHANNELS EINFO_SRP_LOGIN_REJ ( \
94 SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS, \
95 "RDMA channel limit reached for this initiator" )
96#define EPERM_LOGIN_REJ( reason_nibble ) \
97 EUNIQ ( EINFO_EPERM, (reason_nibble), EPERM_UNKNOWN, \
98 EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN, \
99 EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT, \
100 EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS )
101
102/** An SRP device */
104 /** Reference count */
106
107 /** SCSI command issuing interface */
109 /** Underlying data transfer interface */
111
112 /** RDMA memory handle */
114 /** Login completed successfully */
116
117 /** List of active commands */
119};
120
121/** An SRP command */
123 /** Reference count */
125 /** SRP device */
127 /** List of active commands */
129
130 /** SCSI command interface */
132 /** Command tag */
134};
135
136/**
137 * Get reference to SRP device
138 *
139 * @v srpdev SRP device
140 * @ret srpdev SRP device
141 */
142static inline __attribute__ (( always_inline )) struct srp_device *
143srpdev_get ( struct srp_device *srpdev ) {
144 ref_get ( &srpdev->refcnt );
145 return srpdev;
146}
147
148/**
149 * Drop reference to SRP device
150 *
151 * @v srpdev SRP device
152 */
153static inline __attribute__ (( always_inline )) void
154srpdev_put ( struct srp_device *srpdev ) {
155 ref_put ( &srpdev->refcnt );
156}
157
158/**
159 * Get reference to SRP command
160 *
161 * @v srpcmd SRP command
162 * @ret srpcmd SRP command
163 */
164static inline __attribute__ (( always_inline )) struct srp_command *
165srpcmd_get ( struct srp_command *srpcmd ) {
166 ref_get ( &srpcmd->refcnt );
167 return srpcmd;
168}
169
170/**
171 * Drop reference to SRP command
172 *
173 * @v srpcmd SRP command
174 */
175static inline __attribute__ (( always_inline )) void
176srpcmd_put ( struct srp_command *srpcmd ) {
177 ref_put ( &srpcmd->refcnt );
178}
179
180/**
181 * Free SRP command
182 *
183 * @v refcnt Reference count
184 */
185static void srpcmd_free ( struct refcnt *refcnt ) {
186 struct srp_command *srpcmd =
188
189 assert ( list_empty ( &srpcmd->list ) );
190
191 srpdev_put ( srpcmd->srpdev );
192 free ( srpcmd );
193}
194
195/**
196 * Close SRP command
197 *
198 * @v srpcmd SRP command
199 * @v rc Reason for close
200 */
201static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
202 struct srp_device *srpdev = srpcmd->srpdev;
203
204 if ( rc != 0 ) {
205 DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
206 srpdev, srpcmd->tag, strerror ( rc ) );
207 }
208
209 /* Remove from list of commands */
210 if ( ! list_empty ( &srpcmd->list ) ) {
211 list_del ( &srpcmd->list );
212 INIT_LIST_HEAD ( &srpcmd->list );
213 srpcmd_put ( srpcmd );
214 }
215
216 /* Shut down interfaces */
217 intf_shutdown ( &srpcmd->scsi, rc );
218}
219
220/**
221 * Close SRP device
222 *
223 * @v srpdev SRP device
224 * @v rc Reason for close
225 */
226static void srpdev_close ( struct srp_device *srpdev, int rc ) {
227 struct srp_command *srpcmd;
228 struct srp_command *tmp;
229
230 if ( rc != 0 ) {
231 DBGC ( srpdev, "SRP %p closed: %s\n",
232 srpdev, strerror ( rc ) );
233 }
234
235 /* Shut down interfaces */
238
239 /* Shut down any active commands */
241 srpcmd_get ( srpcmd );
242 srpcmd_close ( srpcmd, rc );
243 srpcmd_put ( srpcmd );
244 }
245}
246
247/**
248 * Identify SRP command by tag
249 *
250 * @v srpdev SRP device
251 * @v tag Command tag
252 * @ret srpcmd SRP command, or NULL
253 */
254static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
255 uint32_t tag ) {
256 struct srp_command *srpcmd;
257
258 list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
259 if ( srpcmd->tag == tag )
260 return srpcmd;
261 }
262 return NULL;
263}
264
265/**
266 * Choose an SRP command tag
267 *
268 * @v srpdev SRP device
269 * @ret tag New tag, or negative error
270 */
271static int srp_new_tag ( struct srp_device *srpdev ) {
272 static uint16_t tag_idx;
273 unsigned int i;
274
275 for ( i = 0 ; i < 65536 ; i++ ) {
276 tag_idx++;
277 if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
278 return tag_idx;
279 }
280 return -EADDRINUSE;
281}
282
283/**
284 * Transmit SRP login request
285 *
286 * @v srpdev SRP device
287 * @v initiator Initiator port ID
288 * @v target Target port ID
289 * @v tag Command tag
290 * @ret rc Return status code
291 */
292static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
293 union srp_port_id *target, uint32_t tag ) {
294 struct io_buffer *iobuf;
295 struct srp_login_req *login_req;
296 int rc;
297
298 /* Allocate I/O buffer */
299 iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
300 if ( ! iobuf )
301 return -ENOMEM;
302
303 /* Construct login request IU */
304 login_req = iob_put ( iobuf, sizeof ( *login_req ) );
305 memset ( login_req, 0, sizeof ( *login_req ) );
306 login_req->type = SRP_LOGIN_REQ;
307 login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
308 login_req->tag.dwords[1] = htonl ( tag );
309 login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
311 memcpy ( &login_req->initiator, initiator,
312 sizeof ( login_req->initiator ) );
313 memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
314
315 DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
316 DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
317
318 /* Send login request IU */
319 if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
320 DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
321 "%s\n", srpdev, tag, strerror ( rc ) );
322 return rc;
323 }
324
325 return 0;
326}
327
328/**
329 * Receive SRP login response
330 *
331 * @v srpdev SRP device
332 * @v data SRP IU
333 * @v len Length of SRP IU
334 * @ret rc Return status code
335 */
336static int srp_login_rsp ( struct srp_device *srpdev,
337 const void *data, size_t len ) {
338 const struct srp_login_rsp *login_rsp;
339
340 /* Sanity check */
341 if ( len < sizeof ( *login_rsp ) ) {
342 DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
343 srpdev, len );
344 return -EINVAL;
345 }
346 login_rsp = data;
347 DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
348 srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
349 DBGC_HDA ( srpdev, 0, data, len );
350
351 /* Mark as logged in */
352 srpdev->logged_in = 1;
353 DBGC ( srpdev, "SRP %p logged in\n", srpdev );
354
355 /* Notify of window change */
356 xfer_window_changed ( &srpdev->scsi );
357
358 return 0;
359}
360
361/**
362 * Receive SRP login rejection
363 *
364 * @v srpdev SRP device
365 * @v data SRP IU
366 * @v len Length of SRP IU
367 * @ret rc Return status code
368 */
369static int srp_login_rej ( struct srp_device *srpdev,
370 const void *data, size_t len ) {
371 const struct srp_login_rej *login_rej;
373
374 /* Sanity check */
375 if ( len < sizeof ( *login_rej ) ) {
376 DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
377 srpdev, len );
378 return -EINVAL;
379 }
380 login_rej = data;
381 reason = ntohl ( login_rej->reason );
382 DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
383 srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
384 DBGC_HDA ( srpdev, 0, data, len );
385
386 /* Login rejection always indicates an error */
388 -EPERM_LOGIN_REJ ( reason ) : -EACCES );
389}
390
391/**
392 * Transmit SRP SCSI command
393 *
394 * @v srpdev SRP device
395 * @v command SCSI command
396 * @v tag Command tag
397 * @ret rc Return status code
398 */
399static int srp_cmd ( struct srp_device *srpdev,
400 struct scsi_cmd *command,
401 uint32_t tag ) {
402 struct io_buffer *iobuf;
403 struct srp_cmd *cmd;
404 struct srp_memory_descriptor *data_out;
405 struct srp_memory_descriptor *data_in;
406 int rc;
407
408 /* Sanity check */
409 if ( ! srpdev->logged_in ) {
410 DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
411 "login completes\n", srpdev, tag );
412 return -EBUSY;
413 }
414
415 /* Allocate I/O buffer */
416 iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
417 if ( ! iobuf )
418 return -ENOMEM;
419
420 /* Construct base portion */
421 cmd = iob_put ( iobuf, sizeof ( *cmd ) );
422 memset ( cmd, 0, sizeof ( *cmd ) );
423 cmd->type = SRP_CMD;
424 cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
425 cmd->tag.dwords[1] = htonl ( tag );
426 memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
427 memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
428
429 /* Construct data-out descriptor, if present */
430 if ( command->data_out.len ) {
431 cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
432 data_out = iob_put ( iobuf, sizeof ( *data_out ) );
433 data_out->address =
434 cpu_to_be64 ( virt_to_phys ( command->data_out.data ) );
435 data_out->handle = ntohl ( srpdev->memory_handle );
436 data_out->len = ntohl ( command->data_out.len );
437 }
438
439 /* Construct data-in descriptor, if present */
440 if ( command->data_in.len ) {
441 cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
442 data_in = iob_put ( iobuf, sizeof ( *data_in ) );
443 data_in->address =
444 cpu_to_be64 ( virt_to_phys ( command->data_in.data ) );
445 data_in->handle = ntohl ( srpdev->memory_handle );
446 data_in->len = ntohl ( command->data_in.len );
447 }
448
449 DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
450 srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
451
452 /* Send IU */
453 if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
454 DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
455 srpdev, tag, strerror ( rc ) );
456 return rc;
457 }
458
459 return 0;
460}
461
462/**
463 * Receive SRP SCSI response
464 *
465 * @v srpdev SRP device
466 * @v data SRP IU
467 * @v len Length of SRP IU
468 * @ret rc Returns status code
469 */
470static int srp_rsp ( struct srp_device *srpdev,
471 const void *data, size_t len ) {
472 const struct srp_rsp *rsp;
473 struct srp_command *srpcmd;
474 struct scsi_rsp response;
475 const void *response_data;
476 const void *sense_data;
477 size_t response_data_len;
478 size_t sense_data_len;
479 size_t remaining;
480 ssize_t data_out_residual_count;
481 ssize_t data_in_residual_count;
482
483 /* Parse response */
484 remaining = len;
485 if ( remaining < sizeof ( *rsp ) ) {
486 DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
487 srpdev, len );
488 return -EINVAL;
489 }
490 rsp = data;
491 remaining -= sizeof ( *rsp );
492 DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
493 "%08x valid %02x%s%s%s%s%s%s\n",
494 srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
495 ntohl ( rsp->data_out_residual_count ),
496 ntohl ( rsp->data_in_residual_count ), rsp->valid,
497 ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
498 ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
499 ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
500 ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
501 ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
502 ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
503
504 /* Parse response data */
505 response_data_len = srp_rsp_response_data_len ( rsp );
506 if ( remaining < response_data_len ) {
507 DBGC ( srpdev, "SRP %p RSP overlength response data\n",
508 srpdev );
509 return -EINVAL;
510 }
511 response_data = srp_rsp_response_data ( rsp );
512 if ( response_data ) {
513 DBGC2 ( srpdev, "SRP %p response data:\n", srpdev );
514 DBGC2_HDA ( srpdev, 0, response_data, response_data_len );
515 }
516 remaining -= response_data_len;
517
518 /* Parse sense data */
519 sense_data_len = srp_rsp_sense_data_len ( rsp );
520 if ( remaining < sense_data_len ) {
521 DBGC ( srpdev, "SRP %p RSP overlength sense data\n",
522 srpdev );
523 return -EINVAL;
524 }
525 sense_data = srp_rsp_sense_data ( rsp );
526 if ( sense_data ) {
527 DBGC2 ( srpdev, "SRP %p sense data:\n", srpdev );
528 DBGC2_HDA ( srpdev, 0, sense_data, sense_data_len );
529 }
530 remaining -= sense_data_len;
531
532 /* Identify command by tag */
533 srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
534 if ( ! srpcmd ) {
535 DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
536 srpdev, ntohl ( rsp->tag.dwords[1] ) );
537 return -ENOENT;
538 }
539
540 /* Hold command reference for remainder of function */
541 srpcmd_get ( srpcmd );
542
543 /* Build SCSI response */
544 memset ( &response, 0, sizeof ( response ) );
545 response.status = rsp->status;
546 data_out_residual_count = ntohl ( rsp->data_out_residual_count );
547 data_in_residual_count = ntohl ( rsp->data_in_residual_count );
548 if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
549 response.overrun = data_out_residual_count;
550 } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
551 response.overrun = -(data_out_residual_count);
552 } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
553 response.overrun = data_in_residual_count;
554 } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
555 response.overrun = -(data_in_residual_count);
556 }
557 scsi_parse_sense ( sense_data, sense_data_len, &response.sense );
558
559 /* Report SCSI response */
560 scsi_response ( &srpcmd->scsi, &response );
561
562 /* Close SCSI command */
563 srpcmd_close ( srpcmd, 0 );
564
565 /* Drop temporary command reference */
566 srpcmd_put ( srpcmd );
567
568 return 0;
569}
570
571/**
572 * Receive SRP unrecognised response IU
573 *
574 * @v srpdev SRP device
575 * @v data SRP IU
576 * @v len Length of SRP IU
577 * @ret rc Returns status code
578 */
579static int srp_unrecognised ( struct srp_device *srpdev,
580 const void *data, size_t len ) {
581 const struct srp_common *common = data;
582
583 DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
584 srpdev, ntohl ( common->tag.dwords[1] ), common->type );
585 DBGC_HDA ( srpdev, 0, data, len );
586
587 return -ENOTSUP;
588}
589
590/** SRP command SCSI interface operations */
593};
594
595/** SRP command SCSI interface descriptor */
597 INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
598
599/**
600 * Issue SRP SCSI command
601 *
602 * @v srpdev SRP device
603 * @v parent Parent interface
604 * @v command SCSI command
605 * @ret tag Command tag, or negative error
606 */
607static int srpdev_scsi_command ( struct srp_device *srpdev,
608 struct interface *parent,
609 struct scsi_cmd *command ) {
610 struct srp_command *srpcmd;
611 int tag;
612 int rc;
613
614 /* Allocate command tag */
615 tag = srp_new_tag ( srpdev );
616 if ( tag < 0 ) {
617 rc = tag;
618 goto err_tag;
619 }
620
621 /* Allocate and initialise structure */
622 srpcmd = zalloc ( sizeof ( *srpcmd ) );
623 if ( ! srpcmd ) {
624 rc = -ENOMEM;
625 goto err_zalloc;
626 }
627 ref_init ( &srpcmd->refcnt, srpcmd_free );
628 intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
629 srpcmd->srpdev = srpdev_get ( srpdev );
630 list_add ( &srpcmd->list, &srpdev->commands );
631 srpcmd->tag = tag;
632
633 /* Send command IU */
634 if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
635 goto err_cmd;
636
637 /* Attach to parent interface, leave reference with command
638 * list, and return.
639 */
640 intf_plug_plug ( &srpcmd->scsi, parent );
641 return srpcmd->tag;
642
643 err_cmd:
644 srpcmd_close ( srpcmd, rc );
645 err_zalloc:
646 err_tag:
647 return rc;
648}
649
650/**
651 * Receive data from SRP socket
652 *
653 * @v srpdev SRP device
654 * @v iobuf Datagram I/O buffer
655 * @v meta Data transfer metadata
656 * @ret rc Return status code
657 */
658static int srpdev_deliver ( struct srp_device *srpdev,
659 struct io_buffer *iobuf,
660 struct xfer_metadata *meta __unused ) {
661 struct srp_common *common;
662 int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
663 int rc;
664
665 /* Sanity check */
666 if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
667 DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
668 srpdev, iob_len ( iobuf ) );
669 rc = -EINVAL;
670 goto err;
671 }
672 common = iobuf->data;
673
674 /* Determine IU type */
675 switch ( common->type ) {
676 case SRP_LOGIN_RSP:
678 break;
679 case SRP_LOGIN_REJ:
681 break;
682 case SRP_RSP:
683 type = srp_rsp;
684 break;
685 default:
687 break;
688 }
689
690 /* Handle IU */
691 if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
692 goto err;
693
694 free_iob ( iobuf );
695 return 0;
696
697 err:
698 DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
699 srpdev, strerror ( rc ) );
700 DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
701 free_iob ( iobuf );
702 srpdev_close ( srpdev, rc );
703 return rc;
704}
705
706/**
707 * Check SRP device flow-control window
708 *
709 * @v srpdev SRP device
710 * @ret len Length of window
711 */
712static size_t srpdev_window ( struct srp_device *srpdev ) {
713 return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
714}
715
716/** SRP device socket interface operations */
721
722/** SRP device socket interface descriptor */
725 scsi );
726
727/** SRP device SCSI interface operations */
733
734/** SRP device SCSI interface descriptor */
736 INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket );
737
738/**
739 * Open SRP device
740 *
741 * @v block Block control interface
742 * @v socket Socket interface
743 * @v initiator Initiator port ID
744 * @v target Target port ID
745 * @v memory_handle RDMA memory handle
746 * @v lun SCSI LUN
747 * @ret rc Return status code
748 */
749int srp_open ( struct interface *block, struct interface *socket,
750 union srp_port_id *initiator, union srp_port_id *target,
751 uint32_t memory_handle, struct scsi_lun *lun ) {
752 struct srp_device *srpdev;
753 int tag;
754 int rc;
755
756 /* Allocate and initialise structure */
757 srpdev = zalloc ( sizeof ( *srpdev ) );
758 if ( ! srpdev ) {
759 rc = -ENOMEM;
760 goto err_zalloc;
761 }
762 ref_init ( &srpdev->refcnt, NULL );
763 intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
764 intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
765 INIT_LIST_HEAD ( &srpdev->commands );
767 DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
768 ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
769 ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
770 ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
771 ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
772
773 /* Attach to socket interface and initiate login */
774 intf_plug_plug ( &srpdev->socket, socket );
775 tag = srp_new_tag ( srpdev );
776 assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
777 if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
778 goto err_login;
779
780 /* Attach SCSI device to parent interface */
781 if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
782 DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
783 srpdev, strerror ( rc ) );
784 goto err_scsi_open;
785 }
786
787 /* Mortalise self and return */
788 ref_put ( &srpdev->refcnt );
789 return 0;
790
791 err_scsi_open:
792 err_login:
793 srpdev_close ( srpdev, rc );
794 ref_put ( &srpdev->refcnt );
795 err_zalloc:
796 return rc;
797}
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
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:61
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:598
#define DBGC2(...)
Definition compiler.h:547
#define DBGC2_HDA(...)
Definition compiler.h:548
#define DBGC(...)
Definition compiler.h:530
#define DBGC_HDA(...)
Definition compiler.h:531
#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:921
#define ENOENT
No such file or directory.
Definition errno.h:558
#define EINVAL
Invalid argument.
Definition errno.h:472
#define EADDRINUSE
Address already in use.
Definition errno.h:347
#define ENOMEM
Not enough space.
Definition errno.h:578
#define EBUSY
Device or resource busy.
Definition errno.h:382
#define ENOTSUP
Operation not supported.
Definition errno.h:633
#define EACCES
Permission denied.
Definition errno.h:342
#define SCSI_CDB_DATA(cdb)
printf() parameters for dumping a scsi_cdb
Definition scsi.h:224
#define SCSI_CDB_FORMAT
printf() format for dumping a scsi_cdb
Definition scsi.h:220
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
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:185
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:220
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:718
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:987
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:735
static int srp_cmd(struct srp_device *srpdev, struct scsi_cmd *command, uint32_t tag)
Transmit SRP SCSI command.
Definition srp.c:399
static struct srp_device * srpdev_get(struct srp_device *srpdev)
Get reference to SRP device.
Definition srp.c:143
static struct srp_command * srpcmd_get(struct srp_command *srpcmd)
Get reference to SRP command.
Definition srp.c:165
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:292
static struct srp_command * srp_find_tag(struct srp_device *srpdev, uint32_t tag)
Identify SRP command by tag.
Definition srp.c:254
static struct interface_operation srpdev_scsi_op[]
SRP device SCSI interface operations.
Definition srp.c:728
static int srp_login_rej(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP login rejection.
Definition srp.c:369
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:658
#define SRP_MAX_I_T_IU_LEN
Maximum length of any initiator-to-target IU that we will send.
Definition srp.c:56
static void srpcmd_free(struct refcnt *refcnt)
Free SRP command.
Definition srp.c:185
static size_t srpdev_window(struct srp_device *srpdev)
Check SRP device flow-control window.
Definition srp.c:712
static int srp_login_rsp(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP login response.
Definition srp.c:336
static int srp_unrecognised(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP unrecognised response IU.
Definition srp.c:579
static void srpdev_put(struct srp_device *srpdev)
Drop reference to SRP device.
Definition srp.c:154
static struct interface_operation srpcmd_scsi_op[]
SRP command SCSI interface operations.
Definition srp.c:591
static struct interface_descriptor srpdev_socket_desc
SRP device socket interface descriptor.
Definition srp.c:723
static void srpcmd_close(struct srp_command *srpcmd, int rc)
Close SRP command.
Definition srp.c:201
static void srpcmd_put(struct srp_command *srpcmd)
Drop reference to SRP command.
Definition srp.c:176
static void srpdev_close(struct srp_device *srpdev, int rc)
Close SRP device.
Definition srp.c:226
#define EPERM_LOGIN_REJ(reason_nibble)
Definition srp.c:96
static struct interface_operation srpdev_socket_op[]
SRP device socket interface operations.
Definition srp.c:717
static int srp_rsp(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP SCSI response.
Definition srp.c:470
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:749
static int srpdev_scsi_command(struct srp_device *srpdev, struct interface *parent, struct scsi_cmd *command)
Issue SRP SCSI command.
Definition srp.c:607
static int srp_new_tag(struct srp_device *srpdev)
Choose an SRP command tag.
Definition srp.c:271
static struct interface_descriptor srpcmd_scsi_desc
SRP command SCSI interface descriptor.
Definition srp.c:596
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 const void * srp_rsp_response_data(const struct srp_rsp *rsp)
Get response data portion of SCSI response.
Definition srp.h:588
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:98
void * data
Start of data.
Definition iobuf.h:113
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:250
A SCSI command.
Definition scsi.c:263
A SCSI LUN.
Definition scsi.h:237
A SCSI response information unit.
Definition scsi.h:313
struct scsi_sns_descriptor sense
Autosense data (if any).
Definition scsi.h:324
uint8_t status
SCSI status code.
Definition scsi.h:315
ssize_t overrun
Data overrun (or negative underrun).
Definition scsi.h:317
An SRP SCSI command.
Definition srp.h:415
An SRP command.
Definition srp.c:122
struct list_head list
List of active commands.
Definition srp.c:128
struct refcnt refcnt
Reference count.
Definition srp.c:124
struct srp_device * srpdev
SRP device.
Definition srp.c:126
struct interface scsi
SCSI command interface.
Definition srp.c:131
uint32_t tag
Command tag.
Definition srp.c:133
SRP information unit common fields.
Definition srp.h:43
An SRP device.
Definition srp.c:103
uint32_t memory_handle
RDMA memory handle.
Definition srp.c:113
struct interface socket
Underlying data transfer interface.
Definition srp.c:110
int logged_in
Login completed successfully.
Definition srp.c:115
struct refcnt refcnt
Reference count.
Definition srp.c:105
struct interface scsi
SCSI command issuing interface.
Definition srp.c:108
struct list_head commands
List of active commands.
Definition srp.c:118
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.