|
|
1.1 root 1: /*
2: * Copyright (C) 2009 Fen Systems Ltd <[email protected]>.
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 ( 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: const void *sense;
480: ssize_t data_out_residual_count;
481: ssize_t data_in_residual_count;
482:
483: /* Sanity check */
484: if ( len < sizeof ( *rsp ) ) {
485: DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
486: srpdev, len );
487: return -EINVAL;
488: }
489: DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
490: "%08x valid %02x%s%s%s%s%s%s\n",
491: srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
492: ntohl ( rsp->data_out_residual_count ),
493: ntohl ( rsp->data_in_residual_count ), rsp->valid,
494: ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
495: ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
496: ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
497: ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
498: ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
499: ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
500:
501: /* Identify command by tag */
502: srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
503: if ( ! srpcmd ) {
504: DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
505: srpdev, ntohl ( rsp->tag.dwords[1] ) );
506: return -ENOENT;
507: }
508:
509: /* Hold command reference for remainder of function */
510: srpcmd_get ( srpcmd );
511:
512: /* Build SCSI response */
513: memset ( &response, 0, sizeof ( response ) );
514: response.status = rsp->status;
515: data_out_residual_count = ntohl ( rsp->data_out_residual_count );
516: data_in_residual_count = ntohl ( rsp->data_in_residual_count );
517: if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
518: response.overrun = data_out_residual_count;
519: } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
520: response.overrun = -(data_out_residual_count);
521: } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
522: response.overrun = data_in_residual_count;
523: } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
524: response.overrun = -(data_in_residual_count);
525: }
526: sense = srp_rsp_sense_data ( rsp );
527: if ( sense )
528: memcpy ( &response.sense, sense, sizeof ( response.sense ) );
529:
530: /* Report SCSI response */
531: scsi_response ( &srpcmd->scsi, &response );
532:
533: /* Close SCSI command */
534: srpcmd_close ( srpcmd, 0 );
535:
536: /* Drop temporary command reference */
537: srpcmd_put ( srpcmd );
538:
539: return 0;
540: }
541:
542: /**
543: * Receive SRP unrecognised response IU
544: *
545: * @v srpdev SRP device
546: * @v data SRP IU
547: * @v len Length of SRP IU
548: * @ret rc Returns status code
549: */
550: static int srp_unrecognised ( struct srp_device *srpdev,
551: const void *data, size_t len ) {
552: const struct srp_common *common = data;
553:
554: DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
555: srpdev, ntohl ( common->tag.dwords[1] ), common->type );
556: DBGC_HDA ( srpdev, 0, data, len );
557:
558: return -ENOTSUP;
559: }
560:
561: /** SRP command SCSI interface operations */
562: static struct interface_operation srpcmd_scsi_op[] = {
563: INTF_OP ( intf_close, struct srp_command *, srpcmd_close ),
564: };
565:
566: /** SRP command SCSI interface descriptor */
567: static struct interface_descriptor srpcmd_scsi_desc =
568: INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
569:
570: /**
571: * Issue SRP SCSI command
572: *
573: * @v srpdev SRP device
574: * @v parent Parent interface
575: * @v command SCSI command
576: * @ret tag Command tag, or negative error
577: */
578: static int srpdev_scsi_command ( struct srp_device *srpdev,
579: struct interface *parent,
580: struct scsi_cmd *command ) {
581: struct srp_command *srpcmd;
582: int tag;
583: int rc;
584:
585: /* Allocate command tag */
586: tag = srp_new_tag ( srpdev );
587: if ( tag < 0 ) {
588: rc = tag;
589: goto err_tag;
590: }
591:
592: /* Allocate and initialise structure */
593: srpcmd = zalloc ( sizeof ( *srpcmd ) );
594: if ( ! srpcmd ) {
595: rc = -ENOMEM;
596: goto err_zalloc;
597: }
598: ref_init ( &srpcmd->refcnt, srpcmd_free );
599: intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
600: srpcmd->srpdev = srpdev_get ( srpdev );
601: list_add ( &srpcmd->list, &srpdev->commands );
602: srpcmd->tag = tag;
603:
604: /* Send command IU */
605: if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
606: goto err_cmd;
607:
608: /* Attach to parent interface, leave reference with command
609: * list, and return.
610: */
611: intf_plug_plug ( &srpcmd->scsi, parent );
612: return srpcmd->tag;
613:
614: err_cmd:
615: srpcmd_close ( srpcmd, rc );
616: err_zalloc:
617: err_tag:
618: return rc;
619: }
620:
621: /**
622: * Receive data from SRP socket
623: *
624: * @v srpdev SRP device
625: * @v iobuf Datagram I/O buffer
626: * @v meta Data transfer metadata
627: * @ret rc Return status code
628: */
629: static int srpdev_deliver ( struct srp_device *srpdev,
630: struct io_buffer *iobuf,
631: struct xfer_metadata *meta __unused ) {
632: struct srp_common *common = iobuf->data;
633: int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
634: int rc;
635:
636: /* Sanity check */
637: if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
638: DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
639: srpdev, iob_len ( iobuf ) );
640: rc = -EINVAL;
641: goto err;
642: }
643:
644: /* Determine IU type */
645: switch ( common->type ) {
646: case SRP_LOGIN_RSP:
647: type = srp_login_rsp;
648: break;
649: case SRP_LOGIN_REJ:
650: type = srp_login_rej;
651: break;
652: case SRP_RSP:
653: type = srp_rsp;
654: break;
655: default:
656: type = srp_unrecognised;
657: break;
658: }
659:
660: /* Handle IU */
661: if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
662: goto err;
663:
664: free_iob ( iobuf );
665: return 0;
666:
667: err:
668: DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
669: srpdev, strerror ( rc ) );
670: DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
671: free_iob ( iobuf );
672: srpdev_close ( srpdev, rc );
673: return rc;
674: }
675:
676: /**
677: * Check SRP device flow-control window
678: *
679: * @v srpdev SRP device
680: * @ret len Length of window
681: */
682: static size_t srpdev_window ( struct srp_device *srpdev ) {
683: return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
684: }
685:
686: /**
687: * A (transport-independent) sBFT created by iPXE
688: */
689: struct ipxe_sbft {
690: /** The table header */
691: struct sbft_table table;
692: /** The SCSI subtable */
693: struct sbft_scsi_subtable scsi;
694: /** The SRP subtable */
695: struct sbft_srp_subtable srp;
696: } __attribute__ (( packed, aligned ( 16 ) ));
697:
698: /**
699: * Describe SRP device in an ACPI table
700: *
701: * @v srpdev SRP device
702: * @v acpi ACPI table
703: * @v len Length of ACPI table
704: * @ret rc Return status code
705: */
706: static int srpdev_describe ( struct srp_device *srpdev,
707: struct acpi_description_header *acpi,
708: size_t len ) {
709: struct ipxe_sbft *sbft =
710: container_of ( acpi, struct ipxe_sbft, table.acpi );
711: int rc;
712:
713: /* Sanity check */
714: if ( len < sizeof ( *sbft ) )
715: return -ENOBUFS;
716:
717: /* Populate table */
718: sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
719: sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
720: sbft->table.acpi.revision = 1;
721: sbft->table.scsi_offset =
722: cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
723: memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) );
724: sbft->table.srp_offset =
725: cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
726: memcpy ( &sbft->srp.initiator, &srpdev->initiator,
727: sizeof ( sbft->srp.initiator ) );
728: memcpy ( &sbft->srp.target, &srpdev->target,
729: sizeof ( sbft->srp.target ) );
730:
731: /* Ask transport layer to describe transport-specific portions */
732: if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) {
733: DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n",
734: srpdev, strerror ( rc ) );
735: return rc;
736: }
737:
738: return 0;
739: }
740:
741: /** SRP device socket interface operations */
742: static struct interface_operation srpdev_socket_op[] = {
743: INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
744: INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
745: };
746:
747: /** SRP device socket interface descriptor */
748: static struct interface_descriptor srpdev_socket_desc =
749: INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op,
750: scsi );
751:
752: /** SRP device SCSI interface operations */
753: static struct interface_operation srpdev_scsi_op[] = {
754: INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
755: INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
756: INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
757: INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ),
758: };
759:
760: /** SRP device SCSI interface descriptor */
761: static struct interface_descriptor srpdev_scsi_desc =
762: INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket );
763:
764: /**
765: * Open SRP device
766: *
767: * @v block Block control interface
768: * @v socket Socket interface
769: * @v initiator Initiator port ID
770: * @v target Target port ID
771: * @v memory_handle RDMA memory handle
772: * @v lun SCSI LUN
773: * @ret rc Return status code
774: */
775: int srp_open ( struct interface *block, struct interface *socket,
776: union srp_port_id *initiator, union srp_port_id *target,
777: uint32_t memory_handle, struct scsi_lun *lun ) {
778: struct srp_device *srpdev;
779: int tag;
780: int rc;
781:
782: /* Allocate and initialise structure */
783: srpdev = zalloc ( sizeof ( *srpdev ) );
784: if ( ! srpdev ) {
785: rc = -ENOMEM;
786: goto err_zalloc;
787: }
788: ref_init ( &srpdev->refcnt, NULL );
789: intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
790: intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
791: INIT_LIST_HEAD ( &srpdev->commands );
792: srpdev->memory_handle = memory_handle;
793: DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
794: ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
795: ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
796: ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
797: ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
798:
799: /* Preserve parameters required for boot firmware table */
800: memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) );
801: memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) );
802: memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) );
803:
804: /* Attach to socket interface and initiate login */
805: intf_plug_plug ( &srpdev->socket, socket );
806: tag = srp_new_tag ( srpdev );
807: assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
808: if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
809: goto err_login;
810:
811: /* Attach SCSI device to parent interface */
812: if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
813: DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
814: srpdev, strerror ( rc ) );
815: goto err_scsi_open;
816: }
817:
818: /* Mortalise self and return */
819: ref_put ( &srpdev->refcnt );
820: return 0;
821:
822: err_scsi_open:
823: err_login:
824: srpdev_close ( srpdev, rc );
825: ref_put ( &srpdev->refcnt );
826: err_zalloc:
827: return rc;
828: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.