2 * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
31 FILE_LICENCE ( BSD2
);
36 #include <ipxe/scsi.h>
37 #include <ipxe/xfer.h>
38 #include <ipxe/features.h>
48 FEATURE ( FEATURE_PROTOCOL
, "SRP", DHCP_EB_FEATURE_SRP
, 1 );
50 /** Maximum length of any initiator-to-target IU that we will send
52 * The longest IU is a SRP_CMD with no additional CDB and two direct
53 * data buffer descriptors, which comes to 80 bytes.
55 #define SRP_MAX_I_T_IU_LEN 80
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 )
103 /** Reference count */
104 struct refcnt refcnt
;
106 /** SCSI command issuing interface */
107 struct interface scsi
;
108 /** Underlying data transfer interface */
109 struct interface socket
;
111 /** RDMA memory handle */
112 uint32_t memory_handle
;
113 /** Login completed successfully */
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) */
123 /** List of active commands */
124 struct list_head commands
;
127 /** An SRP command */
129 /** Reference count */
130 struct refcnt refcnt
;
132 struct srp_device
*srpdev
;
133 /** List of active commands */
134 struct list_head list
;
136 /** SCSI command interface */
137 struct interface scsi
;
143 * Get reference to SRP device
145 * @v srpdev SRP device
146 * @ret srpdev SRP device
148 static inline __attribute__ (( always_inline
)) struct srp_device
*
149 srpdev_get ( struct srp_device
*srpdev
) {
150 ref_get ( &srpdev
->refcnt
);
155 * Drop reference to SRP device
157 * @v srpdev SRP device
159 static inline __attribute__ (( always_inline
)) void
160 srpdev_put ( struct srp_device
*srpdev
) {
161 ref_put ( &srpdev
->refcnt
);
165 * Get reference to SRP command
167 * @v srpcmd SRP command
168 * @ret srpcmd SRP command
170 static inline __attribute__ (( always_inline
)) struct srp_command
*
171 srpcmd_get ( struct srp_command
*srpcmd
) {
172 ref_get ( &srpcmd
->refcnt
);
177 * Drop reference to SRP command
179 * @v srpcmd SRP command
181 static inline __attribute__ (( always_inline
)) void
182 srpcmd_put ( struct srp_command
*srpcmd
) {
183 ref_put ( &srpcmd
->refcnt
);
189 * @v refcnt Reference count
191 static void srpcmd_free ( struct refcnt
*refcnt
) {
192 struct srp_command
*srpcmd
=
193 container_of ( refcnt
, struct srp_command
, refcnt
);
195 assert ( list_empty ( &srpcmd
->list
) );
197 srpdev_put ( srpcmd
->srpdev
);
204 * @v srpcmd SRP command
205 * @v rc Reason for close
207 static void srpcmd_close ( struct srp_command
*srpcmd
, int rc
) {
208 struct srp_device
*srpdev
= srpcmd
->srpdev
;
211 DBGC ( srpdev
, "SRP %p tag %08x closed: %s\n",
212 srpdev
, srpcmd
->tag
, strerror ( rc
) );
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
);
222 /* Shut down interfaces */
223 intf_shutdown ( &srpcmd
->scsi
, rc
);
229 * @v srpdev SRP device
230 * @v rc Reason for close
232 static void srpdev_close ( struct srp_device
*srpdev
, int rc
) {
233 struct srp_command
*srpcmd
;
234 struct srp_command
*tmp
;
237 DBGC ( srpdev
, "SRP %p closed: %s\n",
238 srpdev
, strerror ( rc
) );
241 /* Shut down interfaces */
242 intf_shutdown ( &srpdev
->socket
, rc
);
243 intf_shutdown ( &srpdev
->scsi
, rc
);
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
);
254 * Identify SRP command by tag
256 * @v srpdev SRP device
258 * @ret srpcmd SRP command, or NULL
260 static struct srp_command
* srp_find_tag ( struct srp_device
*srpdev
,
262 struct srp_command
*srpcmd
;
264 list_for_each_entry ( srpcmd
, &srpdev
->commands
, list
) {
265 if ( srpcmd
->tag
== tag
)
272 * Choose an SRP command tag
274 * @v srpdev SRP device
275 * @ret tag New tag, or negative error
277 static int srp_new_tag ( struct srp_device
*srpdev
) {
278 static uint16_t tag_idx
;
281 for ( i
= 0 ; i
< 65536 ; i
++ ) {
283 if ( srp_find_tag ( srpdev
, tag_idx
) == NULL
)
290 * Transmit SRP login request
292 * @v srpdev SRP device
293 * @v initiator Initiator port ID
294 * @v target Target port ID
296 * @ret rc Return status code
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
;
304 /* Allocate I/O buffer */
305 iobuf
= xfer_alloc_iob ( &srpdev
->socket
, sizeof ( *login_req
) );
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
) );
321 DBGC ( srpdev
, "SRP %p tag %08x LOGIN_REQ:\n", srpdev
, tag
);
322 DBGC_HDA ( srpdev
, 0, iobuf
->data
, iob_len ( iobuf
) );
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
) );
335 * Receive SRP login response
337 * @v srpdev SRP device
339 * @v len Length of SRP IU
340 * @ret rc Return status code
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
;
347 if ( len
< sizeof ( *login_rsp
) ) {
348 DBGC ( srpdev
, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
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
);
356 /* Mark as logged in */
357 srpdev
->logged_in
= 1;
358 DBGC ( srpdev
, "SRP %p logged in\n", srpdev
);
360 /* Notify of window change */
361 xfer_window_changed ( &srpdev
->scsi
);
367 * Receive SRP login rejection
369 * @v srpdev SRP device
371 * @v len Length of SRP IU
372 * @ret rc Return status code
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
;
380 if ( len
< sizeof ( *login_rej
) ) {
381 DBGC ( srpdev
, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
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
);
390 /* Login rejection always indicates an error */
391 return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason
) ?
392 -EPERM_LOGIN_REJ ( reason
) : -EACCES
);
396 * Transmit SRP SCSI command
398 * @v srpdev SRP device
399 * @v command SCSI command
401 * @ret rc Return status code
403 static int srp_cmd ( struct srp_device
*srpdev
,
404 struct scsi_cmd
*command
,
406 struct io_buffer
*iobuf
;
408 struct srp_memory_descriptor
*data_out
;
409 struct srp_memory_descriptor
*data_in
;
413 if ( ! srpdev
->logged_in
) {
414 DBGC ( srpdev
, "SRP %p tag %08x cannot send CMD before "
415 "login completes\n", srpdev
, tag
);
419 /* Allocate I/O buffer */
420 iobuf
= xfer_alloc_iob ( &srpdev
->socket
, SRP_MAX_I_T_IU_LEN
);
424 /* Construct base portion */
425 cmd
= iob_put ( iobuf
, sizeof ( *cmd
) );
426 memset ( cmd
, 0, sizeof ( *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
) );
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
) );
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
);
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
) );
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
);
453 DBGC2 ( srpdev
, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT
"\n",
454 srpdev
, tag
, SCSI_CDB_DATA ( cmd
->cdb
) );
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
) );
467 * Receive SRP SCSI response
469 * @v srpdev SRP device
471 * @v len Length of SRP IU
472 * @ret rc Returns status code
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
;
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",
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" : "" ) );
503 /* Identify command by tag */
504 srpcmd
= srp_find_tag ( srpdev
, ntohl ( rsp
->tag
.dwords
[1] ) );
506 DBGC ( srpdev
, "SRP %p tag %08x unrecognised RSP\n",
507 srpdev
, ntohl ( rsp
->tag
.dwords
[1] ) );
511 /* Hold command reference for remainder of function */
512 srpcmd_get ( srpcmd
);
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
);
528 scsi_parse_sense ( srp_rsp_sense_data ( rsp
),
529 srp_rsp_sense_data_len ( rsp
), &response
.sense
);
531 /* Report SCSI response */
532 scsi_response ( &srpcmd
->scsi
, &response
);
534 /* Close SCSI command */
535 srpcmd_close ( srpcmd
, 0 );
537 /* Drop temporary command reference */
538 srpcmd_put ( srpcmd
);
544 * Receive SRP unrecognised response IU
546 * @v srpdev SRP device
548 * @v len Length of SRP IU
549 * @ret rc Returns status code
551 static int srp_unrecognised ( struct srp_device
*srpdev
,
552 const void *data
, size_t len
) {
553 const struct srp_common
*common
= data
;
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
);
562 /** SRP command SCSI interface operations */
563 static struct interface_operation srpcmd_scsi_op
[] = {
564 INTF_OP ( intf_close
, struct srp_command
*, srpcmd_close
),
567 /** SRP command SCSI interface descriptor */
568 static struct interface_descriptor srpcmd_scsi_desc
=
569 INTF_DESC ( struct srp_command
, scsi
, srpcmd_scsi_op
);
572 * Issue SRP SCSI command
574 * @v srpdev SRP device
575 * @v parent Parent interface
576 * @v command SCSI command
577 * @ret tag Command tag, or negative error
579 static int srpdev_scsi_command ( struct srp_device
*srpdev
,
580 struct interface
*parent
,
581 struct scsi_cmd
*command
) {
582 struct srp_command
*srpcmd
;
586 /* Allocate command tag */
587 tag
= srp_new_tag ( srpdev
);
593 /* Allocate and initialise structure */
594 srpcmd
= zalloc ( sizeof ( *srpcmd
) );
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
);
605 /* Send command IU */
606 if ( ( rc
= srp_cmd ( srpdev
, command
, srpcmd
->tag
) ) != 0 )
609 /* Attach to parent interface, leave reference with command
612 intf_plug_plug ( &srpcmd
->scsi
, parent
);
616 srpcmd_close ( srpcmd
, rc
);
623 * Receive data from SRP socket
625 * @v srpdev SRP device
626 * @v iobuf Datagram I/O buffer
627 * @v meta Data transfer metadata
628 * @ret rc Return status code
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
);
638 if ( iob_len ( iobuf
) < sizeof ( *common
) ) {
639 DBGC ( srpdev
, "SRP %p IU too short (%zd bytes)\n",
640 srpdev
, iob_len ( iobuf
) );
645 /* Determine IU type */
646 switch ( common
->type
) {
648 type
= srp_login_rsp
;
651 type
= srp_login_rej
;
657 type
= srp_unrecognised
;
662 if ( ( rc
= type ( srpdev
, iobuf
->data
, iob_len ( iobuf
) ) ) != 0 )
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
) );
673 srpdev_close ( srpdev
, rc
);
678 * Check SRP device flow-control window
680 * @v srpdev SRP device
681 * @ret len Length of window
683 static size_t srpdev_window ( struct srp_device
*srpdev
) {
684 return ( srpdev
->logged_in ?
~( ( size_t ) 0 ) : 0 );
688 * A (transport-independent) sBFT created by iPXE
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 ) ));
700 * Describe SRP device in an ACPI table
702 * @v srpdev SRP device
704 * @v len Length of ACPI table
705 * @ret rc Return status code
707 static int srpdev_describe ( struct srp_device
*srpdev
,
708 struct acpi_description_header
*acpi
,
710 struct ipxe_sbft
*sbft
=
711 container_of ( acpi
, struct ipxe_sbft
, table
.acpi
);
715 if ( len
< sizeof ( *sbft
) )
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
) );
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
) );
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
),
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
,
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
),
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
);
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
774 * @ret rc Return status code
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
;
783 /* Allocate and initialise structure */
784 srpdev
= zalloc ( sizeof ( *srpdev
) );
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] ) );
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
) );
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 )
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
) );
819 /* Mortalise self and return */
820 ref_put ( &srpdev
->refcnt
);
825 srpdev_close ( srpdev
, rc
);
826 ref_put ( &srpdev
->refcnt
);