[efi] Implement the EFI_PXE_BASE_CODE_PROTOCOL
[ipxe.git] / src / drivers / block / srp.c
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
48 FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
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 */
109 struct interface socket;
110
111 /** RDMA memory handle */
112 uint32_t memory_handle;
113 /** Login completed successfully */
114 int logged_in;
115
116 /** Initiator port ID (for boot firmware table) */
117 union srp_port_id initiator;
118 /** Target port ID (for boot firmware table) */
119 union srp_port_id target;
120 /** SCSI LUN (for boot firmware table) */
121 struct scsi_lun lun;
122
123 /** List of active commands */
124 struct list_head commands;
125 };
126
127 /** An SRP command */
128 struct srp_command {
129 /** Reference count */
130 struct refcnt refcnt;
131 /** SRP device */
132 struct srp_device *srpdev;
133 /** List of active commands */
134 struct list_head list;
135
136 /** SCSI command interface */
137 struct interface scsi;
138 /** Command tag */
139 uint32_t tag;
140 };
141
142 /**
143 * Get reference to SRP device
144 *
145 * @v srpdev SRP device
146 * @ret srpdev SRP device
147 */
148 static inline __attribute__ (( always_inline )) struct srp_device *
149 srpdev_get ( struct srp_device *srpdev ) {
150 ref_get ( &srpdev->refcnt );
151 return srpdev;
152 }
153
154 /**
155 * Drop reference to SRP device
156 *
157 * @v srpdev SRP device
158 */
159 static inline __attribute__ (( always_inline )) void
160 srpdev_put ( struct srp_device *srpdev ) {
161 ref_put ( &srpdev->refcnt );
162 }
163
164 /**
165 * Get reference to SRP command
166 *
167 * @v srpcmd SRP command
168 * @ret srpcmd SRP command
169 */
170 static inline __attribute__ (( always_inline )) struct srp_command *
171 srpcmd_get ( struct srp_command *srpcmd ) {
172 ref_get ( &srpcmd->refcnt );
173 return srpcmd;
174 }
175
176 /**
177 * Drop reference to SRP command
178 *
179 * @v srpcmd SRP command
180 */
181 static inline __attribute__ (( always_inline )) void
182 srpcmd_put ( struct srp_command *srpcmd ) {
183 ref_put ( &srpcmd->refcnt );
184 }
185
186 /**
187 * Free SRP command
188 *
189 * @v refcnt Reference count
190 */
191 static void srpcmd_free ( struct refcnt *refcnt ) {
192 struct srp_command *srpcmd =
193 container_of ( refcnt, struct srp_command, refcnt );
194
195 assert ( list_empty ( &srpcmd->list ) );
196
197 srpdev_put ( srpcmd->srpdev );
198 free ( srpcmd );
199 }
200
201 /**
202 * Close SRP command
203 *
204 * @v srpcmd SRP command
205 * @v rc Reason for close
206 */
207 static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
208 struct srp_device *srpdev = srpcmd->srpdev;
209
210 if ( rc != 0 ) {
211 DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
212 srpdev, srpcmd->tag, strerror ( rc ) );
213 }
214
215 /* Remove from list of commands */
216 if ( ! list_empty ( &srpcmd->list ) ) {
217 list_del ( &srpcmd->list );
218 INIT_LIST_HEAD ( &srpcmd->list );
219 srpcmd_put ( srpcmd );
220 }
221
222 /* Shut down interfaces */
223 intf_shutdown ( &srpcmd->scsi, rc );
224 }
225
226 /**
227 * Close SRP device
228 *
229 * @v srpdev SRP device
230 * @v rc Reason for close
231 */
232 static void srpdev_close ( struct srp_device *srpdev, int rc ) {
233 struct srp_command *srpcmd;
234 struct srp_command *tmp;
235
236 if ( rc != 0 ) {
237 DBGC ( srpdev, "SRP %p closed: %s\n",
238 srpdev, strerror ( rc ) );
239 }
240
241 /* Shut down interfaces */
242 intf_shutdown ( &srpdev->socket, rc );
243 intf_shutdown ( &srpdev->scsi, rc );
244
245 /* Shut down any active commands */
246 list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) {
247 srpcmd_get ( srpcmd );
248 srpcmd_close ( srpcmd, rc );
249 srpcmd_put ( srpcmd );
250 }
251 }
252
253 /**
254 * Identify SRP command by tag
255 *
256 * @v srpdev SRP device
257 * @v tag Command tag
258 * @ret srpcmd SRP command, or NULL
259 */
260 static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
261 uint32_t tag ) {
262 struct srp_command *srpcmd;
263
264 list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
265 if ( srpcmd->tag == tag )
266 return srpcmd;
267 }
268 return NULL;
269 }
270
271 /**
272 * Choose an SRP command tag
273 *
274 * @v srpdev SRP device
275 * @ret tag New tag, or negative error
276 */
277 static int srp_new_tag ( struct srp_device *srpdev ) {
278 static uint16_t tag_idx;
279 unsigned int i;
280
281 for ( i = 0 ; i < 65536 ; i++ ) {
282 tag_idx++;
283 if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
284 return tag_idx;
285 }
286 return -EADDRINUSE;
287 }
288
289 /**
290 * Transmit SRP login request
291 *
292 * @v srpdev SRP device
293 * @v initiator Initiator port ID
294 * @v target Target port ID
295 * @v tag Command tag
296 * @ret rc Return status code
297 */
298 static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
299 union srp_port_id *target, uint32_t tag ) {
300 struct io_buffer *iobuf;
301 struct srp_login_req *login_req;
302 int rc;
303
304 /* Allocate I/O buffer */
305 iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
306 if ( ! iobuf )
307 return -ENOMEM;
308
309 /* Construct login request IU */
310 login_req = iob_put ( iobuf, sizeof ( *login_req ) );
311 memset ( login_req, 0, sizeof ( *login_req ) );
312 login_req->type = SRP_LOGIN_REQ;
313 login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
314 login_req->tag.dwords[1] = htonl ( tag );
315 login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
316 login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
317 memcpy ( &login_req->initiator, initiator,
318 sizeof ( login_req->initiator ) );
319 memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
320
321 DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
322 DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
323
324 /* Send login request IU */
325 if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
326 DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
327 "%s\n", srpdev, tag, strerror ( rc ) );
328 return rc;
329 }
330
331 return 0;
332 }
333
334 /**
335 * Receive SRP login response
336 *
337 * @v srpdev SRP device
338 * @v data SRP IU
339 * @v len Length of SRP IU
340 * @ret rc Return status code
341 */
342 static int srp_login_rsp ( struct srp_device *srpdev,
343 const void *data, size_t len ) {
344 const struct srp_login_rsp *login_rsp = data;
345
346 /* Sanity check */
347 if ( len < sizeof ( *login_rsp ) ) {
348 DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
349 srpdev, len );
350 return -EINVAL;
351 }
352 DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
353 srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
354 DBGC_HDA ( srpdev, 0, data, len );
355
356 /* Mark as logged in */
357 srpdev->logged_in = 1;
358 DBGC ( srpdev, "SRP %p logged in\n", srpdev );
359
360 /* Notify of window change */
361 xfer_window_changed ( &srpdev->scsi );
362
363 return 0;
364 }
365
366 /**
367 * Receive SRP login rejection
368 *
369 * @v srpdev SRP device
370 * @v data SRP IU
371 * @v len Length of SRP IU
372 * @ret rc Return status code
373 */
374 static int srp_login_rej ( struct srp_device *srpdev,
375 const void *data, size_t len ) {
376 const struct srp_login_rej *login_rej = data;
377 uint32_t reason;
378
379 /* Sanity check */
380 if ( len < sizeof ( *login_rej ) ) {
381 DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
382 srpdev, len );
383 return -EINVAL;
384 }
385 reason = ntohl ( login_rej->reason );
386 DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
387 srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
388 DBGC_HDA ( srpdev, 0, data, len );
389
390 /* Login rejection always indicates an error */
391 return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
392 -EPERM_LOGIN_REJ ( reason ) : -EACCES );
393 }
394
395 /**
396 * Transmit SRP SCSI command
397 *
398 * @v srpdev SRP device
399 * @v command SCSI command
400 * @v tag Command tag
401 * @ret rc Return status code
402 */
403 static int srp_cmd ( struct srp_device *srpdev,
404 struct scsi_cmd *command,
405 uint32_t tag ) {
406 struct io_buffer *iobuf;
407 struct srp_cmd *cmd;
408 struct srp_memory_descriptor *data_out;
409 struct srp_memory_descriptor *data_in;
410 int rc;
411
412 /* Sanity check */
413 if ( ! srpdev->logged_in ) {
414 DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
415 "login completes\n", srpdev, tag );
416 return -EBUSY;
417 }
418
419 /* Allocate I/O buffer */
420 iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
421 if ( ! iobuf )
422 return -ENOMEM;
423
424 /* Construct base portion */
425 cmd = iob_put ( iobuf, sizeof ( *cmd ) );
426 memset ( cmd, 0, sizeof ( *cmd ) );
427 cmd->type = SRP_CMD;
428 cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
429 cmd->tag.dwords[1] = htonl ( tag );
430 memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
431 memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
432
433 /* Construct data-out descriptor, if present */
434 if ( command->data_out ) {
435 cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
436 data_out = iob_put ( iobuf, sizeof ( *data_out ) );
437 data_out->address =
438 cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) );
439 data_out->handle = ntohl ( srpdev->memory_handle );
440 data_out->len = ntohl ( command->data_out_len );
441 }
442
443 /* Construct data-in descriptor, if present */
444 if ( command->data_in ) {
445 cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
446 data_in = iob_put ( iobuf, sizeof ( *data_in ) );
447 data_in->address =
448 cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) );
449 data_in->handle = ntohl ( srpdev->memory_handle );
450 data_in->len = ntohl ( command->data_in_len );
451 }
452
453 DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
454 srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
455
456 /* Send IU */
457 if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
458 DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
459 srpdev, tag, strerror ( rc ) );
460 return rc;
461 }
462
463 return 0;
464 }
465
466 /**
467 * Receive SRP SCSI response
468 *
469 * @v srpdev SRP device
470 * @v data SRP IU
471 * @v len Length of SRP IU
472 * @ret rc Returns status code
473 */
474 static int srp_rsp ( struct srp_device *srpdev,
475 const void *data, size_t len ) {
476 const struct srp_rsp *rsp = data;
477 struct srp_command *srpcmd;
478 struct scsi_rsp response;
479 ssize_t data_out_residual_count;
480 ssize_t data_in_residual_count;
481
482 /* Sanity check */
483 if ( ( len < sizeof ( *rsp ) ) ||
484 ( len < ( sizeof ( *rsp ) +
485 srp_rsp_response_data_len ( rsp ) +
486 srp_rsp_sense_data_len ( rsp ) ) ) ) {
487 DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
488 srpdev, len );
489 return -EINVAL;
490 }
491 DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
492 "%08x valid %02x%s%s%s%s%s%s\n",
493 srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
494 ntohl ( rsp->data_out_residual_count ),
495 ntohl ( rsp->data_in_residual_count ), rsp->valid,
496 ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
497 ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
498 ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
499 ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
500 ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
501 ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
502
503 /* Identify command by tag */
504 srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
505 if ( ! srpcmd ) {
506 DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
507 srpdev, ntohl ( rsp->tag.dwords[1] ) );
508 return -ENOENT;
509 }
510
511 /* Hold command reference for remainder of function */
512 srpcmd_get ( srpcmd );
513
514 /* Build SCSI response */
515 memset ( &response, 0, sizeof ( response ) );
516 response.status = rsp->status;
517 data_out_residual_count = ntohl ( rsp->data_out_residual_count );
518 data_in_residual_count = ntohl ( rsp->data_in_residual_count );
519 if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
520 response.overrun = data_out_residual_count;
521 } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
522 response.overrun = -(data_out_residual_count);
523 } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
524 response.overrun = data_in_residual_count;
525 } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
526 response.overrun = -(data_in_residual_count);
527 }
528 scsi_parse_sense ( srp_rsp_sense_data ( rsp ),
529 srp_rsp_sense_data_len ( rsp ), &response.sense );
530
531 /* Report SCSI response */
532 scsi_response ( &srpcmd->scsi, &response );
533
534 /* Close SCSI command */
535 srpcmd_close ( srpcmd, 0 );
536
537 /* Drop temporary command reference */
538 srpcmd_put ( srpcmd );
539
540 return 0;
541 }
542
543 /**
544 * Receive SRP unrecognised response IU
545 *
546 * @v srpdev SRP device
547 * @v data SRP IU
548 * @v len Length of SRP IU
549 * @ret rc Returns status code
550 */
551 static int srp_unrecognised ( struct srp_device *srpdev,
552 const void *data, size_t len ) {
553 const struct srp_common *common = data;
554
555 DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
556 srpdev, ntohl ( common->tag.dwords[1] ), common->type );
557 DBGC_HDA ( srpdev, 0, data, len );
558
559 return -ENOTSUP;
560 }
561
562 /** SRP command SCSI interface operations */
563 static struct interface_operation srpcmd_scsi_op[] = {
564 INTF_OP ( intf_close, struct srp_command *, srpcmd_close ),
565 };
566
567 /** SRP command SCSI interface descriptor */
568 static struct interface_descriptor srpcmd_scsi_desc =
569 INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
570
571 /**
572 * Issue SRP SCSI command
573 *
574 * @v srpdev SRP device
575 * @v parent Parent interface
576 * @v command SCSI command
577 * @ret tag Command tag, or negative error
578 */
579 static int srpdev_scsi_command ( struct srp_device *srpdev,
580 struct interface *parent,
581 struct scsi_cmd *command ) {
582 struct srp_command *srpcmd;
583 int tag;
584 int rc;
585
586 /* Allocate command tag */
587 tag = srp_new_tag ( srpdev );
588 if ( tag < 0 ) {
589 rc = tag;
590 goto err_tag;
591 }
592
593 /* Allocate and initialise structure */
594 srpcmd = zalloc ( sizeof ( *srpcmd ) );
595 if ( ! srpcmd ) {
596 rc = -ENOMEM;
597 goto err_zalloc;
598 }
599 ref_init ( &srpcmd->refcnt, srpcmd_free );
600 intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
601 srpcmd->srpdev = srpdev_get ( srpdev );
602 list_add ( &srpcmd->list, &srpdev->commands );
603 srpcmd->tag = tag;
604
605 /* Send command IU */
606 if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
607 goto err_cmd;
608
609 /* Attach to parent interface, leave reference with command
610 * list, and return.
611 */
612 intf_plug_plug ( &srpcmd->scsi, parent );
613 return srpcmd->tag;
614
615 err_cmd:
616 srpcmd_close ( srpcmd, rc );
617 err_zalloc:
618 err_tag:
619 return rc;
620 }
621
622 /**
623 * Receive data from SRP socket
624 *
625 * @v srpdev SRP device
626 * @v iobuf Datagram I/O buffer
627 * @v meta Data transfer metadata
628 * @ret rc Return status code
629 */
630 static int srpdev_deliver ( struct srp_device *srpdev,
631 struct io_buffer *iobuf,
632 struct xfer_metadata *meta __unused ) {
633 struct srp_common *common = iobuf->data;
634 int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
635 int rc;
636
637 /* Sanity check */
638 if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
639 DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
640 srpdev, iob_len ( iobuf ) );
641 rc = -EINVAL;
642 goto err;
643 }
644
645 /* Determine IU type */
646 switch ( common->type ) {
647 case SRP_LOGIN_RSP:
648 type = srp_login_rsp;
649 break;
650 case SRP_LOGIN_REJ:
651 type = srp_login_rej;
652 break;
653 case SRP_RSP:
654 type = srp_rsp;
655 break;
656 default:
657 type = srp_unrecognised;
658 break;
659 }
660
661 /* Handle IU */
662 if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
663 goto err;
664
665 free_iob ( iobuf );
666 return 0;
667
668 err:
669 DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
670 srpdev, strerror ( rc ) );
671 DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
672 free_iob ( iobuf );
673 srpdev_close ( srpdev, rc );
674 return rc;
675 }
676
677 /**
678 * Check SRP device flow-control window
679 *
680 * @v srpdev SRP device
681 * @ret len Length of window
682 */
683 static size_t srpdev_window ( struct srp_device *srpdev ) {
684 return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
685 }
686
687 /**
688 * A (transport-independent) sBFT created by iPXE
689 */
690 struct ipxe_sbft {
691 /** The table header */
692 struct sbft_table table;
693 /** The SCSI subtable */
694 struct sbft_scsi_subtable scsi;
695 /** The SRP subtable */
696 struct sbft_srp_subtable srp;
697 } __attribute__ (( packed, aligned ( 16 ) ));
698
699 /**
700 * Describe SRP device in an ACPI table
701 *
702 * @v srpdev SRP device
703 * @v acpi ACPI table
704 * @v len Length of ACPI table
705 * @ret rc Return status code
706 */
707 static int srpdev_describe ( struct srp_device *srpdev,
708 struct acpi_description_header *acpi,
709 size_t len ) {
710 struct ipxe_sbft *sbft =
711 container_of ( acpi, struct ipxe_sbft, table.acpi );
712 int rc;
713
714 /* Sanity check */
715 if ( len < sizeof ( *sbft ) )
716 return -ENOBUFS;
717
718 /* Populate table */
719 sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
720 sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
721 sbft->table.acpi.revision = 1;
722 sbft->table.scsi_offset =
723 cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
724 memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) );
725 sbft->table.srp_offset =
726 cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
727 memcpy ( &sbft->srp.initiator, &srpdev->initiator,
728 sizeof ( sbft->srp.initiator ) );
729 memcpy ( &sbft->srp.target, &srpdev->target,
730 sizeof ( sbft->srp.target ) );
731
732 /* Ask transport layer to describe transport-specific portions */
733 if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) {
734 DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n",
735 srpdev, strerror ( rc ) );
736 return rc;
737 }
738
739 return 0;
740 }
741
742 /** SRP device socket interface operations */
743 static struct interface_operation srpdev_socket_op[] = {
744 INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
745 INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
746 };
747
748 /** SRP device socket interface descriptor */
749 static struct interface_descriptor srpdev_socket_desc =
750 INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op,
751 scsi );
752
753 /** SRP device SCSI interface operations */
754 static struct interface_operation srpdev_scsi_op[] = {
755 INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
756 INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
757 INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
758 INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ),
759 };
760
761 /** SRP device SCSI interface descriptor */
762 static struct interface_descriptor srpdev_scsi_desc =
763 INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket );
764
765 /**
766 * Open SRP device
767 *
768 * @v block Block control interface
769 * @v socket Socket interface
770 * @v initiator Initiator port ID
771 * @v target Target port ID
772 * @v memory_handle RDMA memory handle
773 * @v lun SCSI LUN
774 * @ret rc Return status code
775 */
776 int srp_open ( struct interface *block, struct interface *socket,
777 union srp_port_id *initiator, union srp_port_id *target,
778 uint32_t memory_handle, struct scsi_lun *lun ) {
779 struct srp_device *srpdev;
780 int tag;
781 int rc;
782
783 /* Allocate and initialise structure */
784 srpdev = zalloc ( sizeof ( *srpdev ) );
785 if ( ! srpdev ) {
786 rc = -ENOMEM;
787 goto err_zalloc;
788 }
789 ref_init ( &srpdev->refcnt, NULL );
790 intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
791 intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
792 INIT_LIST_HEAD ( &srpdev->commands );
793 srpdev->memory_handle = memory_handle;
794 DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
795 ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
796 ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
797 ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
798 ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
799
800 /* Preserve parameters required for boot firmware table */
801 memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) );
802 memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) );
803 memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) );
804
805 /* Attach to socket interface and initiate login */
806 intf_plug_plug ( &srpdev->socket, socket );
807 tag = srp_new_tag ( srpdev );
808 assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
809 if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
810 goto err_login;
811
812 /* Attach SCSI device to parent interface */
813 if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
814 DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
815 srpdev, strerror ( rc ) );
816 goto err_scsi_open;
817 }
818
819 /* Mortalise self and return */
820 ref_put ( &srpdev->refcnt );
821 return 0;
822
823 err_scsi_open:
824 err_login:
825 srpdev_close ( srpdev, rc );
826 ref_put ( &srpdev->refcnt );
827 err_zalloc:
828 return rc;
829 }