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 
31 FILE_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 */
102 struct srp_device {
103  /** Reference count */
104  struct refcnt refcnt;
105 
106  /** SCSI command issuing interface */
107  struct interface scsi;
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 */
121 struct srp_command {
122  /** Reference count */
123  struct refcnt refcnt;
124  /** SRP device */
126  /** List of active commands */
127  struct list_head list;
128 
129  /** SCSI command interface */
130  struct interface scsi;
131  /** Command tag */
133 };
134 
135 /**
136  * Get reference to SRP device
137  *
138  * @v srpdev SRP device
139  * @ret srpdev SRP device
140  */
141 static inline __attribute__ (( always_inline )) struct srp_device *
142 srpdev_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  */
152 static inline __attribute__ (( always_inline )) void
153 srpdev_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  */
163 static inline __attribute__ (( always_inline )) struct srp_command *
164 srpcmd_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  */
174 static inline __attribute__ (( always_inline )) void
175 srpcmd_put ( struct srp_command *srpcmd ) {
176  ref_put ( &srpcmd->refcnt );
177 }
178 
179 /**
180  * Free SRP command
181  *
182  * @v refcnt Reference count
183  */
184 static void srpcmd_free ( struct refcnt *refcnt ) {
185  struct srp_command *srpcmd =
186  container_of ( refcnt, struct srp_command, refcnt );
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  */
200 static 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  */
225 static 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 */
235  intf_shutdown ( &srpdev->socket, rc );
236  intf_shutdown ( &srpdev->scsi, rc );
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  */
253 static 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  */
270 static 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  */
291 static 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  */
335 static 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  */
367 static 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 */
384  return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
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  */
396 static 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 ( user_to_phys ( command->data_out, 0 ) );
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 ( user_to_phys ( command->data_in, 0 ) );
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  */
467 static 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  */
544 static 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  */
572 static 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  */
623 static 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  */
676 static 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 */
683  INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
684 };
685 
686 /** SRP device socket interface descriptor */
689  scsi );
690 
691 /** SRP device SCSI interface operations */
695  INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
696 };
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  */
713 int 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 );
730  srpdev->memory_handle = memory_handle;
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 }
static void srpdev_close(struct srp_device *srpdev, int rc)
Close SRP device.
Definition: srp.c:225
void scsi_parse_sense(const void *data, size_t len, struct scsi_sns_descriptor *sense)
Parse SCSI sense data.
Definition: scsi.c:146
#define __attribute__(x)
Definition: compiler.h:10
union srp_port_id initiator
Initiator port identifier.
Definition: srp.h:89
#define EINVAL
Invalid argument.
Definition: errno.h:428
An SRP port ID.
Definition: srp.h:36
An object interface operation.
Definition: interface.h:17
#define SRP_LOGIN_REQ_FMT_DDBD
Require direct data buffer descriptor format.
Definition: srp.h:101
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
void xfer_window_changed(struct interface *intf)
Report change of flow control window.
Definition: xfer.c:146
unsigned short uint16_t
Definition: stdint.h:11
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition: interface.c:249
#define iob_put(iobuf, len)
Definition: iobuf.h:120
Data transfer metadata.
Definition: xfer.h:22
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition: interface.c:278
uint8_t type
Information unit type.
Definition: srp.h:64
struct refcnt refcnt
Reference count.
Definition: srp.c:104
int xfer_deliver_iob(struct interface *intf, struct io_buffer *iobuf)
Deliver datagram as I/O buffer without metadata.
Definition: xfer.c:255
uint32_t dwords[4]
Definition: srp.h:38
SRP information unit common fields.
Definition: srp.h:42
#define EBUSY
Device or resource busy.
Definition: errno.h:338
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
#define SRP_RSP
Type of an SRP SCSI response.
Definition: srp.h:558
An SRP login request information unit.
Definition: srp.h:59
#define SRP_TAG_MAGIC
SRP tag magic marker.
Definition: srp.h:33
#define SRP_MAX_I_T_IU_LEN
Maximum length of any initiator-to-target IU that we will send.
Definition: srp.c:55
uint32_t len
Data length.
Definition: srp.h:505
struct srp_device * srpdev
SRP device.
Definition: srp.c:125
#define FEATURE_PROTOCOL
Network protocols.
Definition: features.h:21
uint64_t address
Virtual address.
Definition: srp.h:501
#define list_add(new, head)
Add a new entry to the head of a list.
Definition: list.h:69
static struct interface_descriptor srpdev_socket_desc
SRP device socket interface descriptor.
Definition: srp.c:687
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:64
Error codes.
An SRP SCSI response.
Definition: srp.h:516
A command-line command.
Definition: command.h:9
static struct interface_operation srpcmd_scsi_op[]
SRP command SCSI interface operations.
Definition: srp.c:556
#define SRP_RSP_VALID_DIUNDER
Data-in residual count field is valid and represents an underflow.
Definition: srp.h:564
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:146
uint32_t type
Operating system type.
Definition: ena.h:12
#define EADDRINUSE
Address already in use.
Definition: errno.h:303
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
#define SRP_LOGIN_REJ
Type of an SRP login rejection.
Definition: srp.h:222
#define DBGC(...)
Definition: compiler.h:505
#define SRP_RSP_VALID_SNSVALID
Sense data list length field is valid.
Definition: srp.h:576
static void srpdev_put(struct srp_device *srpdev)
Drop reference to SRP device.
Definition: srp.c:153
#define ENOENT
No such file or directory.
Definition: errno.h:514
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition: interface.c:107
static int srpdev_scsi_command(struct srp_device *srpdev, struct interface *parent, struct scsi_cmd *command)
Issue SRP SCSI command.
Definition: srp.c:572
#define SRP_LOGIN_REJ_REASON_DEFINED(reason)
SRP login rejection reason is defined.
Definition: srp.h:246
union srp_tag tag
Tag.
Definition: srp.h:208
#define ntohl(value)
Definition: byteswap.h:134
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition: xfer.c:158
#define EACCES
Permission denied.
Definition: errno.h:298
#define SRP_RSP_VALID_DOOVER
Data-out residual count field is valid and represents an overflow.
Definition: srp.h:573
int scsi_open(struct interface *block, struct interface *scsi, struct scsi_lun *lun)
Open SCSI device.
Definition: scsi.c:984
struct list_head list
List of active commands.
Definition: srp.c:127
#define htonl(value)
Definition: byteswap.h:133
size_t xfer_window(struct interface *intf)
Check flow control window.
Definition: xfer.c:116
#define DHCP_EB_FEATURE_SRP
SRP protocol.
Definition: features.h:47
static int srp_login_rsp(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP login response.
Definition: srp.c:335
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
A doubly-linked list entry (or list head)
Definition: list.h:18
Data transfer interfaces.
A reference counter.
Definition: refcnt.h:26
uint32_t tag
Command tag.
Definition: srp.c:132
SCSI RDMA Protocol.
#define list_empty(list)
Test whether a list is empty.
Definition: list.h:136
static void srpcmd_put(struct srp_command *srpcmd)
Drop reference to SRP command.
Definition: srp.c:175
unsigned long tmp
Definition: linux_pci.h:63
struct list_head commands
List of active commands.
Definition: srp.c:117
FILE_LICENCE(BSD2)
#define SRP_CMD_DI_FMT_DIRECT
Direct data-in buffer format.
Definition: srp.h:481
#define list_del(list)
Delete an entry from a list.
Definition: list.h:119
#define SRP_CMD
Type of an SRP SCSI command.
Definition: srp.h:460
#define SRP_LOGIN_RSP
Type of an SRP login response.
Definition: srp.h:163
#define ENOMEM
Not enough space.
Definition: errno.h:534
static void srpcmd_free(struct refcnt *refcnt)
Free SRP command.
Definition: srp.c:184
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static struct interface_operation srpdev_scsi_op[]
SRP device SCSI interface operations.
Definition: srp.c:692
#define SRP_CMD_DO_FMT_DIRECT
Direct data-out buffer format.
Definition: srp.h:472
An SRP SCSI command.
Definition: srp.h:414
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
A SCSI command.
Definition: scsi.c:262
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
An object interface.
Definition: interface.h:124
A SCSI response information unit.
Definition: scsi.h:322
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition: list.h:431
#define DBGC_HDA(...)
Definition: compiler.h:506
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
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:621
union srp_tag tag
Tag.
Definition: srp.h:68
Feature list.
static struct interface_descriptor srpcmd_scsi_desc
SRP command SCSI interface descriptor.
Definition: srp.c:561
uint8_t lun
Logical Unit Number.
Definition: edd.h:32
static int srp_unrecognised(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP unrecognised response IU.
Definition: srp.c:544
#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:458
static int srp_new_tag(struct srp_device *srpdev)
Choose an SRP command tag.
Definition: srp.c:270
int meta(WINDOW *, bool)
uint32_t handle
Memory handle.
Definition: srp.h:503
static struct srp_command * srp_find_tag(struct srp_device *srpdev, uint32_t tag)
Identify SRP command by tag.
Definition: srp.c:253
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:598
uint64_t rsp
Definition: librm.h:267
An object interface descriptor.
Definition: interface.h:55
An SRP login response.
Definition: srp.h:129
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
uint32_t memory_handle
RDMA memory handle.
Definition: srp.c:112
#define ref_get(refcnt)
Get additional reference to object.
Definition: refcnt.h:92
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:155
uint8_t status
SCSI status code.
Definition: scsi.h:324
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition: interface.h:32
static int srp_cmd(struct srp_device *srpdev, struct scsi_cmd *command, uint32_t tag)
Transmit SRP SCSI command.
Definition: srp.c:396
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:194
static int srp_login_rej(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP login rejection.
Definition: srp.c:367
#define SCSI_CDB_DATA(cdb)
printf() parameters for dumping a scsi_cdb
Definition: scsi.h:223
union srp_tag tag
Tag.
Definition: srp.h:140
static struct interface_descriptor srpdev_scsi_desc
SRP device SCSI interface descriptor.
Definition: srp.c:699
union srp_port_id target
Target port identifier.
Definition: srp.h:91
unsigned int uint32_t
Definition: stdint.h:12
uint16_t required_buffer_formats
Required buffer formats.
Definition: srp.h:78
An SRP device.
Definition: srp.c:102
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
struct ib_cm_common common
Definition: ib_mad.h:11
struct interface scsi
SCSI command interface.
Definition: srp.c:130
static size_t srpdev_window(struct srp_device *srpdev)
Check SRP device flow-control window.
Definition: srp.c:676
An SRP login rejection.
Definition: srp.h:194
static struct srp_device * srpdev_get(struct srp_device *srpdev)
Get reference to SRP device.
Definition: srp.c:142
struct refcnt refcnt
Reference count.
Definition: srp.c:123
void scsi_response(struct interface *intf, struct scsi_rsp *response)
Report SCSI response.
Definition: scsi.c:206
SCSI devices.
A SCSI command information unit.
Definition: scsi.h:249
static int srp_rsp(struct srp_device *srpdev, const void *data, size_t len)
Receive SRP SCSI response.
Definition: srp.c:467
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition: list.h:45
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition: interface.h:80
struct interface scsi
SCSI command issuing interface.
Definition: srp.c:107
int logged_in
Login completed successfully.
Definition: srp.c:114
uint32_t reason
Reason.
Definition: srp.h:206
#define SCSI_CDB_FORMAT
printf() format for dumping a scsi_cdb
Definition: scsi.h:219
#define DBGC2(...)
Definition: compiler.h:522
uint8_t block[3][8]
DES-encrypted blocks.
Definition: mschapv2.h:12
#define SRP_RSP_VALID_DOUNDER
Data-out residual count field is valid and represents an underflow.
Definition: srp.h:570
struct scsi_sns_descriptor sense
Autosense data (if any)
Definition: scsi.h:333
An SRP command.
Definition: srp.c:121
void * data
Start of data.
Definition: iobuf.h:48
#define SRP_RSP_VALID_DIOVER
Data-in residual count field is valid and represents an overflow.
Definition: srp.h:567
struct interface socket
Underlying data transfer interface.
Definition: srp.c:109
static struct interface_operation srpdev_socket_op[]
SRP device socket interface operations.
Definition: srp.c:681
#define cpu_to_be64(value)
Definition: byteswap.h:111
uint8_t data[48]
Additional event data.
Definition: ena.h:22
uint16_t reason
Rejection reason.
Definition: ib_mad.h:20
An SRP memory descriptor.
Definition: srp.h:499
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 INTF_DESC_PASSTHRU(object_type, intf, operations, passthru)
Define an object interface descriptor with pass-through interface.
Definition: interface.h:97
static struct srp_command * srpcmd_get(struct srp_command *srpcmd)
Get reference to SRP command.
Definition: srp.c:164
A SCSI LUN.
Definition: scsi.h:236
#define EPERM_LOGIN_REJ(reason_nibble)
Definition: srp.c:95
signed long ssize_t
Definition: stdint.h:7
uint32_t dwords[2]
Definition: srp.h:29
#define SRP_LOGIN_REQ
Type of an SRP login request.
Definition: srp.h:95
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition: interface.h:203
uint64_t tag
Identity tag.
Definition: edd.h:30
uint32_t max_i_t_iu_len
Requested maximum initiator to target IU length.
Definition: srp.h:70
uint32_t len
Length.
Definition: ena.h:14
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
struct golan_eqe_cmd cmd
Definition: CIB_PRM.h:29
String functions.
FEATURE(FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1)
#define SRP_RSP_VALID_RSPVALID
Response data list length field is valid.
Definition: srp.h:579
static void srpcmd_close(struct srp_command *srpcmd, int rc)
Close SRP command.
Definition: srp.c:200
static const void * srp_rsp_sense_data(const struct srp_rsp *rsp)
Get sense data portion of SCSI response.
Definition: srp.h:609
ssize_t overrun
Data overrun (or negative underrun)
Definition: scsi.h:326
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:106
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:33