|
|
1.1 root 1: /*
2: * Copyright (C) 2010 Michael Brown <[email protected]>.
3: *
4: * This program is free software; you can redistribute it and/or
5: * modify it under the terms of the GNU General Public License as
6: * published by the Free Software Foundation; either version 2 of the
7: * License, or any later version.
8: *
9: * This program is distributed in the hope that it will be useful, but
10: * WITHOUT ANY WARRANTY; without even the implied warranty of
11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12: * General Public License for more details.
13: *
14: * You should have received a copy of the GNU General Public License
15: * along with this program; if not, write to the Free Software
16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: FILE_LICENCE ( GPL2_OR_LATER );
20:
21: #include <stddef.h>
22: #include <stdint.h>
23: #include <stdlib.h>
24: #include <string.h>
25: #include <errno.h>
26: #include <stdio.h>
27: #include <assert.h>
28: #include <byteswap.h>
29: #include <ipxe/refcnt.h>
30: #include <ipxe/list.h>
31: #include <ipxe/interface.h>
32: #include <ipxe/xfer.h>
33: #include <ipxe/iobuf.h>
34: #include <ipxe/open.h>
35: #include <ipxe/process.h>
36: #include <ipxe/uri.h>
37: #include <ipxe/acpi.h>
38: #include <ipxe/scsi.h>
39: #include <ipxe/device.h>
40: #include <ipxe/edd.h>
41: #include <ipxe/fc.h>
42: #include <ipxe/fcels.h>
43: #include <ipxe/fcp.h>
44:
45: /** @file
46: *
47: * Fibre Channel Protocol
48: *
49: */
50:
51: /* Disambiguate the various error causes */
52: #define ERANGE_READ_DATA_ORDERING \
53: __einfo_error ( EINFO_ERANGE_READ_DATA_ORDERING )
54: #define EINFO_ERANGE_READ_DATA_ORDERING \
55: __einfo_uniqify ( EINFO_ERANGE, 0x01, "Read data out of order" )
56: #define ERANGE_READ_DATA_OVERRUN \
57: __einfo_error ( EINFO_ERANGE_READ_DATA_OVERRUN )
58: #define EINFO_ERANGE_READ_DATA_OVERRUN \
59: __einfo_uniqify ( EINFO_ERANGE, 0x02, "Read data overrun" )
60: #define ERANGE_WRITE_DATA_STUCK \
61: __einfo_error ( EINFO_ERANGE_WRITE_DATA_STUCK )
62: #define EINFO_ERANGE_WRITE_DATA_STUCK \
63: __einfo_uniqify ( EINFO_ERANGE, 0x03, "Write data stuck" )
64: #define ERANGE_WRITE_DATA_OVERRUN \
65: __einfo_error ( EINFO_ERANGE_WRITE_DATA_OVERRUN )
66: #define EINFO_ERANGE_WRITE_DATA_OVERRUN \
67: __einfo_uniqify ( EINFO_ERANGE, 0x04, "Write data overrun" )
68: #define ERANGE_DATA_UNDERRUN \
69: __einfo_error ( EINFO_ERANGE_DATA_UNDERRUN )
70: #define EINFO_ERANGE_DATA_UNDERRUN \
71: __einfo_uniqify ( EINFO_ERANGE, 0x05, "Data underrun" )
72:
73: /******************************************************************************
74: *
75: * PRLI
76: *
77: ******************************************************************************
78: */
79:
80: struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor;
81:
82: /**
83: * Transmit FCP PRLI
84: *
85: * @v els Fibre Channel ELS transaction
86: * @ret rc Return status code
87: */
88: static int fcp_prli_tx ( struct fc_els *els ) {
89: struct fcp_prli_service_parameters param;
90:
91: /* Build service parameter page */
92: memset ( ¶m, 0, sizeof ( param ) );
93: param.flags = htonl ( FCP_PRLI_NO_READ_RDY | FCP_PRLI_INITIATOR );
94:
95: return fc_els_prli_tx ( els, &fcp_prli_descriptor, ¶m );
96: }
97:
98: /**
99: * Receive FCP PRLI
100: *
101: * @v els Fibre Channel ELS transaction
102: * @v frame ELS frame
103: * @v len Length of ELS frame
104: * @ret rc Return status code
105: */
106: static int fcp_prli_rx ( struct fc_els *els, void *data, size_t len ) {
107: return fc_els_prli_rx ( els, &fcp_prli_descriptor, data, len );
108: }
109:
110: /**
111: * Detect FCP PRLI
112: *
113: * @v els Fibre Channel ELS transaction
114: * @v data ELS frame
115: * @v len Length of ELS frame
116: * @ret rc Return status code
117: */
118: static int fcp_prli_detect ( struct fc_els *els, const void *data,
119: size_t len ) {
120: return fc_els_prli_detect ( els, &fcp_prli_descriptor, data, len );
121: }
122:
123: /** FCP PRLI ELS handler */
124: struct fc_els_handler fcp_prli_handler __fc_els_handler = {
125: .name = "PRLI-FCP",
126: .tx = fcp_prli_tx,
127: .rx = fcp_prli_rx,
128: .detect = fcp_prli_detect,
129: };
130:
131: /** FCP PRLI descriptor */
132: struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor = {
133: .type = FC_TYPE_FCP,
134: .param_len = sizeof ( struct fcp_prli_service_parameters ),
135: .handler = &fcp_prli_handler,
136: };
137:
138: /******************************************************************************
139: *
140: * FCP devices and commands
141: *
142: ******************************************************************************
143: */
144:
145: /** An FCP device */
146: struct fcp_device {
147: /** Reference count */
148: struct refcnt refcnt;
149: /** Fibre Channel upper-layer protocol */
150: struct fc_ulp *ulp;
151: /** SCSI command issuing interface */
152: struct interface scsi;
153: /** List of active commands */
154: struct list_head fcpcmds;
155:
156: /** Fibre Channel WWN (for boot firmware table) */
157: struct fc_name wwn;
158: /** SCSI LUN (for boot firmware table) */
159: struct scsi_lun lun;
160: };
161:
162: /** An FCP command */
163: struct fcp_command {
164: /** Reference count */
165: struct refcnt refcnt;
166: /** FCP SCSI device */
167: struct fcp_device *fcpdev;
168: /** List of active commands */
169: struct list_head list;
170: /** SCSI command interface */
171: struct interface scsi;
172: /** Fibre Channel exchange interface */
173: struct interface xchg;
174: /** Send process */
175: struct process process;
176: /** Send current IU
177: *
178: * @v fcpcmd FCP command
179: * @ret rc Return status code
180: */
181: int ( * send ) ( struct fcp_command *fcpcmd );
182: /** SCSI command */
183: struct scsi_cmd command;
184: /** Data offset within command */
185: size_t offset;
186: /** Length of data remaining to be sent within this IU */
187: size_t remaining;
188: /** Exchange ID */
189: uint16_t xchg_id;
190: };
191:
192: /**
193: * Get reference to FCP device
194: *
195: * @v fcpdev FCP device
196: * @ret fcpdev FCP device
197: */
198: static inline __attribute__ (( always_inline )) struct fcp_device *
199: fcpdev_get ( struct fcp_device *fcpdev ) {
200: ref_get ( &fcpdev->refcnt );
201: return fcpdev;
202: }
203:
204: /**
205: * Drop reference to FCP device
206: *
207: * @v fcpdev FCP device
208: */
209: static inline __attribute__ (( always_inline )) void
210: fcpdev_put ( struct fcp_device *fcpdev ) {
211: ref_put ( &fcpdev->refcnt );
212: }
213:
214: /**
215: * Get reference to FCP command
216: *
217: * @v fcpcmd FCP command
218: * @ret fcpcmd FCP command
219: */
220: static inline __attribute__ (( always_inline )) struct fcp_command *
221: fcpcmd_get ( struct fcp_command *fcpcmd ) {
222: ref_get ( &fcpcmd->refcnt );
223: return fcpcmd;
224: }
225:
226: /**
227: * Drop reference to FCP command
228: *
229: * @v fcpcmd FCP command
230: */
231: static inline __attribute__ (( always_inline )) void
232: fcpcmd_put ( struct fcp_command *fcpcmd ) {
233: ref_put ( &fcpcmd->refcnt );
234: }
235:
236: /**
237: * Start FCP command sending
238: *
239: * @v fcpcmd FCP command
240: * @v send Send method
241: */
242: static inline __attribute__ (( always_inline )) void
243: fcpcmd_start_send ( struct fcp_command *fcpcmd,
244: int ( * send ) ( struct fcp_command *fcpcmd ) ) {
245: fcpcmd->send = send;
246: process_add ( &fcpcmd->process );
247: }
248:
249: /**
250: * Stop FCP command sending
251: *
252: * @v fcpcmd FCP command
253: */
254: static inline __attribute__ (( always_inline )) void
255: fcpcmd_stop_send ( struct fcp_command *fcpcmd ) {
256: process_del ( &fcpcmd->process );
257: }
258:
259: /**
260: * Free FCP command
261: *
262: * @v refcnt Reference count
263: */
264: static void fcpcmd_free ( struct refcnt *refcnt ) {
265: struct fcp_command *fcpcmd =
266: container_of ( refcnt, struct fcp_command, refcnt );
267:
268: /* Remove from list of commands */
269: list_del ( &fcpcmd->list );
270: fcpdev_put ( fcpcmd->fcpdev );
271:
272: /* Free command */
273: free ( fcpcmd );
274: }
275:
276: /**
277: * Close FCP command
278: *
279: * @v fcpcmd FCP command
280: * @v rc Reason for close
281: */
282: static void fcpcmd_close ( struct fcp_command *fcpcmd, int rc ) {
283: struct fcp_device *fcpdev = fcpcmd->fcpdev;
284:
285: if ( rc != 0 ) {
286: DBGC ( fcpdev, "FCP %p xchg %04x closed: %s\n",
287: fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
288: }
289:
290: /* Stop sending */
291: fcpcmd_stop_send ( fcpcmd );
292:
293: /* Shut down interfaces */
294: intf_shutdown ( &fcpcmd->scsi, rc );
295: intf_shutdown ( &fcpcmd->xchg, rc );
296: }
297:
298: /**
299: * Close FCP command in error
300: *
301: * @v fcpcmd FCP command
302: * @v rc Reason for close
303: */
304: static void fcpcmd_close_err ( struct fcp_command *fcpcmd, int rc ) {
305: if ( rc == 0 )
306: rc = -EPIPE;
307: fcpcmd_close ( fcpcmd, rc );
308: }
309:
310: /**
311: * Send FCP command IU
312: *
313: * @v fcpcmd FCP command
314: * @ret rc Return status code
315: */
316: static int fcpcmd_send_cmnd ( struct fcp_command *fcpcmd ) {
317: struct fcp_device *fcpdev = fcpcmd->fcpdev;
318: struct scsi_cmd *command = &fcpcmd->command;
319: struct io_buffer *iobuf;
320: struct fcp_cmnd *cmnd;
321: struct xfer_metadata meta;
322: int rc;
323:
324: /* Sanity check */
325: if ( command->data_in_len && command->data_out_len ) {
326: DBGC ( fcpdev, "FCP %p xchg %04x cannot handle bidirectional "
327: "command\n", fcpdev, fcpcmd->xchg_id );
328: return -ENOTSUP;
329: }
330:
331: /* Allocate I/O buffer */
332: iobuf = xfer_alloc_iob ( &fcpcmd->xchg, sizeof ( *cmnd ) );
333: if ( ! iobuf ) {
334: DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate command IU\n",
335: fcpdev, fcpcmd->xchg_id );
336: return -ENOMEM;
337: }
338:
339: /* Construct command IU frame */
340: cmnd = iob_put ( iobuf, sizeof ( *cmnd ) );
341: memset ( cmnd, 0, sizeof ( *cmnd ) );
342: memcpy ( &cmnd->lun, &command->lun, sizeof ( cmnd->lun ) );
343: assert ( ! ( command->data_in_len && command->data_out_len ) );
344: if ( command->data_in_len )
345: cmnd->dirn |= FCP_CMND_RDDATA;
346: if ( command->data_out_len )
347: cmnd->dirn |= FCP_CMND_WRDATA;
348: memcpy ( &cmnd->cdb, &fcpcmd->command.cdb, sizeof ( cmnd->cdb ) );
349: cmnd->len = htonl ( command->data_in_len + command->data_out_len );
350: memset ( &meta, 0, sizeof ( meta ) );
351: meta.flags = ( XFER_FL_CMD_STAT | XFER_FL_OVER );
352: DBGC2 ( fcpdev, "FCP %p xchg %04x CMND " SCSI_CDB_FORMAT " %04x\n",
353: fcpdev, fcpcmd->xchg_id, SCSI_CDB_DATA ( cmnd->cdb ),
354: ntohl ( cmnd->len ) );
355:
356: /* No further data to send within this IU */
357: fcpcmd_stop_send ( fcpcmd );
358:
359: /* Send command IU frame */
360: if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ),
361: &meta ) ) != 0 ) {
362: DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver command IU: "
363: "%s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
364: return rc;
365: }
366:
367: return 0;
368: }
369:
370: /**
371: * Handle FCP read data IU
372: *
373: * @v fcpcmd FCP command
374: * @v iobuf I/O buffer
375: * @v meta Data transfer metadata
376: * @ret rc Return status code
377: */
378: static int fcpcmd_recv_rddata ( struct fcp_command *fcpcmd,
379: struct io_buffer *iobuf,
380: struct xfer_metadata *meta ) {
381: struct fcp_device *fcpdev = fcpcmd->fcpdev;
382: struct scsi_cmd *command = &fcpcmd->command;
383: size_t offset = meta->offset;
384: size_t len = iob_len ( iobuf );
385: int rc;
386:
387: /* Sanity checks */
388: if ( ! ( meta->flags & XFER_FL_ABS_OFFSET ) ) {
389: DBGC ( fcpdev, "FCP %p xchg %04x read data missing offset\n",
390: fcpdev, fcpcmd->xchg_id );
391: rc = -ERANGE_READ_DATA_ORDERING;
392: goto done;
393: }
394: if ( offset != fcpcmd->offset ) {
395: DBGC ( fcpdev, "FCP %p xchg %04x read data out of order "
396: "(expected %zd, received %zd)\n",
397: fcpdev, fcpcmd->xchg_id, fcpcmd->offset, offset );
398: rc = -ERANGE_READ_DATA_ORDERING;
399: goto done;
400: }
401: if ( ( offset + len ) > command->data_in_len ) {
402: DBGC ( fcpdev, "FCP %p xchg %04x read data overrun (max %zd, "
403: "received %zd)\n", fcpdev, fcpcmd->xchg_id,
404: command->data_in_len, ( offset + len ) );
405: rc = -ERANGE_READ_DATA_OVERRUN;
406: goto done;
407: }
408: DBGC2 ( fcpdev, "FCP %p xchg %04x RDDATA [%08zx,%08zx)\n",
409: fcpdev, fcpcmd->xchg_id, offset, ( offset + len ) );
410:
411: /* Copy to user buffer */
412: copy_to_user ( command->data_in, offset, iobuf->data, len );
413: fcpcmd->offset += len;
414: assert ( fcpcmd->offset <= command->data_in_len );
415:
416: rc = 0;
417: done:
418: free_iob ( iobuf );
419: return rc;
420: }
421:
422: /**
423: * Send FCP write data IU
424: *
425: * @v fcpcmd FCP command
426: * @ret rc Return status code
427: */
428: static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) {
429: struct fcp_device *fcpdev = fcpcmd->fcpdev;
430: struct scsi_cmd *command = &fcpcmd->command;
431: struct io_buffer *iobuf;
432: struct xfer_metadata meta;
433: size_t len;
434: int rc;
435:
436: /* Calculate length to be sent */
437: len = xfer_window ( &fcpcmd->xchg );
438: if ( len > fcpcmd->remaining )
439: len = fcpcmd->remaining;
440:
441: /* Sanity checks */
442: if ( len == 0 ) {
443: DBGC ( fcpdev, "FCP %p xchg %04x write data stuck\n",
444: fcpdev, fcpcmd->xchg_id );
445: return -ERANGE_WRITE_DATA_STUCK;
446: }
447: if ( ( fcpcmd->offset + len ) > command->data_out_len ) {
448: DBGC ( fcpdev, "FCP %p xchg %04x write data overrun (max %zd, "
449: "requested %zd)\n", fcpdev, fcpcmd->xchg_id,
450: command->data_out_len, ( fcpcmd->offset + len ) );
451: return -ERANGE_WRITE_DATA_OVERRUN;
452: }
453:
454: /* Allocate I/O buffer */
455: iobuf = xfer_alloc_iob ( &fcpcmd->xchg, len );
456: if ( ! iobuf ) {
457: DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate write data "
458: "IU for %zd bytes\n", fcpdev, fcpcmd->xchg_id, len );
459: return -ENOMEM;
460: }
461:
462: /* Construct data IU frame */
463: copy_from_user ( iob_put ( iobuf, len ), command->data_out,
464: fcpcmd->offset, len );
465: memset ( &meta, 0, sizeof ( meta ) );
466: meta.flags = ( XFER_FL_RESPONSE | XFER_FL_ABS_OFFSET );
467: meta.offset = fcpcmd->offset;
468: DBGC2 ( fcpdev, "FCP %p xchg %04x WRDATA [%08zx,%04zx)\n",
469: fcpdev, fcpcmd->xchg_id, fcpcmd->offset,
470: ( fcpcmd->offset + iob_len ( iobuf ) ) );
471:
472: /* Calculate amount of data remaining to be sent within this IU */
473: assert ( len <= fcpcmd->remaining );
474: fcpcmd->offset += len;
475: fcpcmd->remaining -= len;
476: assert ( fcpcmd->offset <= command->data_out_len );
477: if ( fcpcmd->remaining == 0 ) {
478: fcpcmd_stop_send ( fcpcmd );
479: meta.flags |= XFER_FL_OVER;
480: }
481:
482: /* Send data IU frame */
483: if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ),
484: &meta ) ) != 0 ) {
485: DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver write data "
486: "IU: %s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
487: return rc;
488: }
489:
490: return 0;
491: }
492:
493: /**
494: * Handle FCP transfer ready IU
495: *
496: * @v fcpcmd FCP command
497: * @v iobuf I/O buffer
498: * @v meta Data transfer metadata
499: * @ret rc Return status code
500: */
501: static int fcpcmd_recv_xfer_rdy ( struct fcp_command *fcpcmd,
502: struct io_buffer *iobuf,
503: struct xfer_metadata *meta __unused ) {
504: struct fcp_device *fcpdev = fcpcmd->fcpdev;
505: struct fcp_xfer_rdy *xfer_rdy = iobuf->data;
506: int rc;
507:
508: /* Sanity checks */
509: if ( iob_len ( iobuf ) != sizeof ( *xfer_rdy ) ) {
510: DBGC ( fcpdev, "FCP %p xchg %04x received invalid transfer "
511: "ready IU:\n", fcpdev, fcpcmd->xchg_id );
512: DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
513: rc = -EPROTO;
514: goto done;
515: }
516: if ( ntohl ( xfer_rdy->offset ) != fcpcmd->offset ) {
517: /* We do not advertise out-of-order delivery */
518: DBGC ( fcpdev, "FCP %p xchg %04x cannot support out-of-order "
519: "delivery (expected %zd, requested %d)\n",
520: fcpdev, fcpcmd->xchg_id, fcpcmd->offset,
521: ntohl ( xfer_rdy->offset ) );
522: rc = -EPROTO;
523: goto done;
524: }
525: DBGC2 ( fcpdev, "FCP %p xchg %04x XFER_RDY [%08x,%08x)\n",
526: fcpdev, fcpcmd->xchg_id, ntohl ( xfer_rdy->offset ),
527: ( ntohl ( xfer_rdy->offset ) + ntohl ( xfer_rdy->len ) ) );
528:
529: /* Start sending requested data */
530: fcpcmd->remaining = ntohl ( xfer_rdy->len );
531: fcpcmd_start_send ( fcpcmd, fcpcmd_send_wrdata );
532:
533: rc = 0;
534: done:
535: free_iob ( iobuf );
536: return rc;
537: }
538:
539: /**
540: * Handle FCP response IU
541: *
542: * @v fcpcmd FCP command
543: * @v iobuf I/O buffer
544: * @v meta Data transfer metadata
545: * @ret rc Return status code
546: */
547: static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd,
548: struct io_buffer *iobuf,
549: struct xfer_metadata *meta __unused ) {
550: struct fcp_device *fcpdev = fcpcmd->fcpdev;
551: struct scsi_cmd *command = &fcpcmd->command;
552: struct fcp_rsp *rsp = iobuf->data;
553: struct scsi_sense *sense;
554: struct scsi_rsp response;
555: int rc;
556:
557: /* Sanity check */
558: if ( ( iob_len ( iobuf ) < sizeof ( *rsp ) ) ||
559: ( iob_len ( iobuf ) < ( sizeof ( *rsp ) +
560: fcp_rsp_response_data_len ( rsp ) +
561: fcp_rsp_sense_data_len ( rsp ) ) ) ) {
562: DBGC ( fcpdev, "FCP %p xchg %04x received invalid response "
563: "IU:\n", fcpdev, fcpcmd->xchg_id );
564: DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
565: rc = -EPROTO;
566: goto done;
567: }
568: DBGC2 ( fcpdev, "FCP %p xchg %04x RSP stat %02x resid %08x flags %02x"
569: "%s%s%s%s\n", fcpdev, fcpcmd->xchg_id, rsp->status,
570: ntohl ( rsp->residual ), rsp->flags,
571: ( ( rsp->flags & FCP_RSP_RESPONSE_LEN_VALID ) ? " resp" : "" ),
572: ( ( rsp->flags & FCP_RSP_SENSE_LEN_VALID ) ? " sense" : "" ),
573: ( ( rsp->flags & FCP_RSP_RESIDUAL_OVERRUN ) ? " over" : "" ),
574: ( ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) ? " under" : "" ));
575: if ( fcp_rsp_response_data ( rsp ) ) {
576: DBGC2 ( fcpdev, "FCP %p xchg %04x response data:\n",
577: fcpdev, fcpcmd->xchg_id );
578: DBGC2_HDA ( fcpdev, 0, fcp_rsp_response_data ( rsp ),
579: fcp_rsp_response_data_len ( rsp ) );
580: }
581: if ( fcp_rsp_sense_data ( rsp ) ) {
582: DBGC2 ( fcpdev, "FCP %p xchg %04x sense data:\n",
583: fcpdev, fcpcmd->xchg_id );
584: DBGC2_HDA ( fcpdev, 0, fcp_rsp_sense_data ( rsp ),
585: fcp_rsp_sense_data_len ( rsp ) );
586: }
587:
588: /* Check for locally-detected command underrun */
589: if ( ( rsp->status == 0 ) &&
590: ( fcpcmd->offset != ( command->data_in_len +
591: command->data_out_len ) ) ) {
592: DBGC ( fcpdev, "FCP %p xchg %04x data underrun (expected %zd, "
593: "got %zd)\n", fcpdev, fcpcmd->xchg_id,
594: ( command->data_in_len + command->data_out_len ),
595: fcpcmd->offset );
596: rc = -ERANGE_DATA_UNDERRUN;
597: goto done;
598: }
599:
600: /* Build SCSI response */
601: memset ( &response, 0, sizeof ( response ) );
602: response.status = rsp->status;
603: if ( rsp->flags & ( FCP_RSP_RESIDUAL_OVERRUN |
604: FCP_RSP_RESIDUAL_UNDERRUN ) ) {
605: response.overrun = ntohl ( rsp->residual );
606: if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN )
607: response.overrun = -response.overrun;
608: }
609: if ( ( sense = fcp_rsp_sense_data ( rsp ) ) != NULL )
610: memcpy ( &response.sense, sense, sizeof ( response.sense ) );
611:
612: /* Free buffer before sending response, to minimise
613: * out-of-memory errors.
614: */
615: free_iob ( iob_disown ( iobuf ) );
616:
617: /* Send SCSI response */
618: scsi_response ( &fcpcmd->scsi, &response );
619:
620: /* Terminate command */
621: fcpcmd_close ( fcpcmd, 0 );
622:
623: rc = 0;
624: done:
625: free_iob ( iobuf );
626: return rc;
627: }
628:
629: /**
630: * Handle unknown FCP IU
631: *
632: * @v fcpcmd FCP command
633: * @v iobuf I/O buffer
634: * @v meta Data transfer metadata
635: * @ret rc Return status code
636: */
637: static int fcpcmd_recv_unknown ( struct fcp_command *fcpcmd,
638: struct io_buffer *iobuf,
639: struct xfer_metadata *meta __unused ) {
640: struct fcp_device *fcpdev = fcpcmd->fcpdev;
641:
642: DBGC ( fcpdev, "FCP %p xchg %04x received unknown IU:\n",
643: fcpdev, fcpcmd->xchg_id );
644: DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
645: free_iob ( iobuf );
646: return -EPROTO;
647: }
648:
649: /**
650: * Transmit FCP frame
651: *
652: * @v process FCP command process
653: */
654: static void fcpcmd_step ( struct process *process ) {
655: struct fcp_command *fcpcmd =
656: container_of ( process, struct fcp_command, process );
657: int rc;
658:
659: /* Send the current IU */
660: if ( ( rc = fcpcmd->send ( fcpcmd ) ) != 0 ) {
661: /* Treat failure as a fatal error */
662: fcpcmd_close ( fcpcmd, rc );
663: }
664: }
665:
666: /**
667: * Receive FCP frame
668: *
669: * @v fcpcmd FCP command
670: * @v iobuf I/O buffer
671: * @v meta Data transfer metadata
672: * @ret rc Return status code
673: */
674: static int fcpcmd_deliver ( struct fcp_command *fcpcmd,
675: struct io_buffer *iobuf,
676: struct xfer_metadata *meta ) {
677: int ( * fcpcmd_recv ) ( struct fcp_command *fcpcmd,
678: struct io_buffer *iobuf,
679: struct xfer_metadata *meta );
680: int rc;
681:
682: /* Determine handler */
683: switch ( meta->flags & ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) {
684: case ( XFER_FL_RESPONSE ) :
685: fcpcmd_recv = fcpcmd_recv_rddata;
686: break;
687: case ( XFER_FL_CMD_STAT ) :
688: fcpcmd_recv = fcpcmd_recv_xfer_rdy;
689: break;
690: case ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) :
691: fcpcmd_recv = fcpcmd_recv_rsp;
692: break;
693: default:
694: fcpcmd_recv = fcpcmd_recv_unknown;
695: break;
696: }
697:
698: /* Handle IU */
699: if ( ( rc = fcpcmd_recv ( fcpcmd, iob_disown ( iobuf ), meta ) ) != 0 ){
700: /* Treat any error as fatal to the command */
701: fcpcmd_close ( fcpcmd, rc );
702: }
703:
704: return rc;
705: }
706:
707: /** FCP command SCSI interface operations */
708: static struct interface_operation fcpcmd_scsi_op[] = {
709: INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close ),
710: };
711:
712: /** FCP command SCSI interface descriptor */
713: static struct interface_descriptor fcpcmd_scsi_desc =
714: INTF_DESC_PASSTHRU ( struct fcp_command, scsi, fcpcmd_scsi_op, xchg );
715:
716: /** FCP command Fibre Channel exchange interface operations */
717: static struct interface_operation fcpcmd_xchg_op[] = {
718: INTF_OP ( xfer_deliver, struct fcp_command *, fcpcmd_deliver ),
719: INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close_err ),
720: };
721:
722: /** FCP command Fibre Channel exchange interface descriptor */
723: static struct interface_descriptor fcpcmd_xchg_desc =
724: INTF_DESC_PASSTHRU ( struct fcp_command, xchg, fcpcmd_xchg_op, scsi );
725:
726: /**
727: * Issue FCP SCSI command
728: *
729: * @v fcpdev FCP device
730: * @v parent Parent interface
731: * @v command SCSI command
732: * @ret tag Command tag, or negative error
733: */
734: static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
735: struct interface *parent,
736: struct scsi_cmd *command ) {
737: struct fcp_prli_service_parameters *param = fcpdev->ulp->param;
738: struct fcp_command *fcpcmd;
739: int xchg_id;
740: int rc;
741:
742: /* Check link */
743: if ( ( rc = fcpdev->ulp->link.rc ) != 0 ) {
744: DBGC ( fcpdev, "FCP %p could not issue command while link is "
745: "down: %s\n", fcpdev, strerror ( rc ) );
746: goto err_link;
747: }
748:
749: /* Check target capability */
750: assert ( param != NULL );
751: assert ( fcpdev->ulp->param_len >= sizeof ( *param ) );
752: if ( ! ( param->flags & htonl ( FCP_PRLI_TARGET ) ) ) {
753: DBGC ( fcpdev, "FCP %p could not issue command: not a target\n",
754: fcpdev );
755: rc = -ENOTTY;
756: goto err_target;
757: }
758:
759: /* Allocate and initialise structure */
760: fcpcmd = zalloc ( sizeof ( *fcpcmd ) );
761: if ( ! fcpcmd ) {
762: rc = -ENOMEM;
763: goto err_zalloc;
764: }
765: ref_init ( &fcpcmd->refcnt, fcpcmd_free );
766: intf_init ( &fcpcmd->scsi, &fcpcmd_scsi_desc, &fcpcmd->refcnt );
767: intf_init ( &fcpcmd->xchg, &fcpcmd_xchg_desc, &fcpcmd->refcnt );
768: process_init_stopped ( &fcpcmd->process, fcpcmd_step, &fcpcmd->refcnt );
769: fcpcmd->fcpdev = fcpdev_get ( fcpdev );
770: list_add ( &fcpcmd->list, &fcpdev->fcpcmds );
771: memcpy ( &fcpcmd->command, command, sizeof ( fcpcmd->command ) );
772:
773: /* Create new exchange */
774: if ( ( xchg_id = fc_xchg_originate ( &fcpcmd->xchg,
775: fcpdev->ulp->peer->port,
776: &fcpdev->ulp->peer->port_id,
777: FC_TYPE_FCP ) ) < 0 ) {
778: rc = xchg_id;
779: DBGC ( fcpdev, "FCP %p could not create exchange: %s\n",
780: fcpdev, strerror ( rc ) );
781: goto err_xchg_originate;
782: }
783: fcpcmd->xchg_id = xchg_id;
784:
785: /* Start sending command IU */
786: fcpcmd_start_send ( fcpcmd, fcpcmd_send_cmnd );
787:
788: /* Attach to parent interface, mortalise self, and return */
789: intf_plug_plug ( &fcpcmd->scsi, parent );
790: ref_put ( &fcpcmd->refcnt );
791: return ( FCP_TAG_MAGIC | fcpcmd->xchg_id );
792:
793: err_xchg_originate:
794: fcpcmd_close ( fcpcmd, rc );
795: ref_put ( &fcpcmd->refcnt );
796: err_zalloc:
797: err_target:
798: err_link:
799: return rc;
800: }
801:
802: /**
803: * Close FCP device
804: *
805: * @v fcpdev FCP device
806: * @v rc Reason for close
807: */
808: static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) {
809: struct fcp_command *fcpcmd;
810: struct fcp_command *tmp;
811:
812: DBGC ( fcpdev, "FCP %p closed: %s\n", fcpdev, strerror ( rc ) );
813:
814: /* Shut down interfaces */
815: intf_shutdown ( &fcpdev->scsi, rc );
816:
817: /* Shut down any active commands */
818: list_for_each_entry_safe ( fcpcmd, tmp, &fcpdev->fcpcmds, list ) {
819: fcpcmd_get ( fcpcmd );
820: fcpcmd_close ( fcpcmd, rc );
821: fcpcmd_put ( fcpcmd );
822: }
823:
824: /* Drop reference to ULP */
825: if ( fcpdev->ulp ) {
826: fc_ulp_decrement ( fcpdev->ulp );
827: fc_ulp_put ( fcpdev->ulp );
828: fcpdev->ulp = NULL;
829: }
830: }
831:
832: /**
833: * Check FCP device flow-control window
834: *
835: * @v fcpdev FCP device
836: * @ret len Length of window
837: */
838: static size_t fcpdev_window ( struct fcp_device *fcpdev ) {
839: return ( fc_link_ok ( &fcpdev->ulp->link ) ? ~( ( size_t ) 0 ) : 0 );
840: }
841:
842: /**
843: * Describe FCP device in an ACPI table
844: *
845: * @v fcpdev FCP device
846: * @v acpi ACPI table
847: * @v len Length of ACPI table
848: * @ret rc Return status code
849: */
850: static int fcpdev_acpi_describe ( struct fcp_device *fcpdev,
851: struct acpi_description_header *acpi,
852: size_t len ) {
853:
854: DBGC ( fcpdev, "FCP %p cannot yet describe device in an ACPI table\n",
855: fcpdev );
856: ( void ) acpi;
857: ( void ) len;
858: return 0;
859: }
860:
861: /**
862: * Describe FCP device using EDD
863: *
864: * @v fcpdev FCP device
865: * @v type EDD interface type
866: * @v path EDD device path
867: * @ret rc Return status code
868: */
869: static int fcpdev_edd_describe ( struct fcp_device *fcpdev,
870: struct edd_interface_type *type,
871: union edd_device_path *path ) {
872: union {
873: struct fc_name fc;
874: uint64_t u64;
875: } wwn;
876: union {
877: struct scsi_lun scsi;
878: uint64_t u64;
879: } lun;
880:
881: type->type = cpu_to_le64 ( EDD_INTF_TYPE_FIBRE );
882: memcpy ( &wwn.fc, &fcpdev->wwn, sizeof ( wwn.fc ) );
883: path->fibre.wwn = be64_to_cpu ( wwn.u64 );
884: memcpy ( &lun.scsi, &fcpdev->lun, sizeof ( lun.scsi ) );
885: path->fibre.lun = be64_to_cpu ( lun.u64 );
886: return 0;
887: }
888:
889: /**
890: * Identify device underlying FCP device
891: *
892: * @v fcpdev FCP device
893: * @ret device Underlying device
894: */
895: static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) {
896:
897: /* We know the underlying device only if the link is up;
898: * otherwise we don't have a port to examine.
899: */
900: if ( ! fc_link_ok ( &fcpdev->ulp->link ) ) {
901: DBGC ( fcpdev, "FCP %p doesn't know underlying device "
902: "until link is up\n", fcpdev );
903: return NULL;
904: }
905:
906: /* Hand off to port's transport interface */
907: assert ( fcpdev->ulp->peer->port != NULL );
908: return identify_device ( &fcpdev->ulp->peer->port->transport );
909: }
910:
911: /** FCP device SCSI interface operations */
912: static struct interface_operation fcpdev_scsi_op[] = {
913: INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ),
914: INTF_OP ( xfer_window, struct fcp_device *, fcpdev_window ),
915: INTF_OP ( intf_close, struct fcp_device *, fcpdev_close ),
916: INTF_OP ( acpi_describe, struct fcp_device *, fcpdev_acpi_describe ),
917: INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ),
918: INTF_OP ( identify_device, struct fcp_device *,
919: fcpdev_identify_device ),
920: };
921:
922: /** FCP device SCSI interface descriptor */
923: static struct interface_descriptor fcpdev_scsi_desc =
924: INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op );
925:
926: /**
927: * Open FCP device
928: *
929: * @v parent Parent interface
930: * @v wwn Fibre Channel WWN
931: * @v lun SCSI LUN
932: * @ret rc Return status code
933: */
934: static int fcpdev_open ( struct interface *parent, struct fc_name *wwn,
935: struct scsi_lun *lun ) {
936: struct fc_ulp *ulp;
937: struct fcp_device *fcpdev;
938: int rc;
939:
940: /* Get Fibre Channel ULP interface */
941: ulp = fc_ulp_get_wwn_type ( wwn, FC_TYPE_FCP );
942: if ( ! ulp ) {
943: rc = -ENOMEM;
944: goto err_ulp_get;
945: }
946:
947: /* Allocate and initialise structure */
948: fcpdev = zalloc ( sizeof ( *fcpdev ) );
949: if ( ! fcpdev ) {
950: rc = -ENOMEM;
951: goto err_zalloc;
952: }
953: ref_init ( &fcpdev->refcnt, NULL );
954: intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt );
955: INIT_LIST_HEAD ( &fcpdev->fcpcmds );
956: fcpdev->ulp = fc_ulp_get ( ulp );
957: fc_ulp_increment ( fcpdev->ulp );
958:
959: DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) );
960:
961: /* Preserve parameters required for boot firmware table */
962: memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) );
963: memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) );
964:
965: /* Attach SCSI device to parent interface */
966: if ( ( rc = scsi_open ( parent, &fcpdev->scsi, lun ) ) != 0 ) {
967: DBGC ( fcpdev, "FCP %p could not create SCSI device: %s\n",
968: fcpdev, strerror ( rc ) );
969: goto err_scsi_open;
970: }
971:
972: /* Drop temporary reference to ULP */
973: fc_ulp_put ( ulp );
974:
975: /* Mortalise self and return */
976: ref_put ( &fcpdev->refcnt );
977: return 0;
978:
979: err_scsi_open:
980: fcpdev_close ( fcpdev, rc );
981: ref_put ( &fcpdev->refcnt );
982: err_zalloc:
983: fc_ulp_put ( ulp );
984: err_ulp_get:
985: return rc;
986: }
987:
988: /******************************************************************************
989: *
990: * FCP URIs
991: *
992: ******************************************************************************
993: */
994:
995: /**
996: * Parse FCP URI
997: *
998: * @v uri URI
999: * @ret wwn Fibre Channel WWN
1000: * @ret lun SCSI LUN
1001: * @ret rc Return status code
1002: *
1003: * An FCP URI has the form "fcp:<wwn>:<lun>" or "fcp://<wwn>/<lun>"
1004: */
1005: static int fcp_parse_uri ( struct uri *uri, struct fc_name *wwn,
1006: struct scsi_lun *lun ) {
1007: char wwn_buf[ FC_NAME_STRLEN + 1 /* NUL */ ];
1008: const char *wwn_text;
1009: const char *lun_text;
1010: int rc;
1011:
1012: /* Extract WWN and LUN texts from URI */
1013: if ( uri->opaque ) {
1014: /* "fcp:<wwn>:<lun>" */
1015: if ( snprintf ( wwn_buf, sizeof ( wwn_buf ), "%s",
1016: uri->opaque ) < ( FC_NAME_STRLEN + 1 /* : */ ) )
1017: return -EINVAL;
1018: if ( uri->opaque[FC_NAME_STRLEN] != ':' )
1019: return -EINVAL;
1020: wwn_text = wwn_buf;
1021: lun_text = &uri->opaque[FC_NAME_STRLEN + 1];
1022: } else {
1023: /* If host exists, path must also exist */
1024: if ( ! ( uri->host && uri->path ) )
1025: return -EINVAL;
1026: if ( uri->path[0] != '/' )
1027: return -EINVAL;
1028: wwn_text = uri->host;
1029: lun_text = ( uri->path + 1 );
1030: }
1031:
1032: /* Parse WWN */
1033: if ( ( rc = fc_aton ( wwn_text, wwn ) ) != 0 )
1034: return rc;
1035:
1036: /* Parse LUN */
1037: if ( ( rc = scsi_parse_lun ( lun_text, lun ) ) != 0 )
1038: return rc;
1039:
1040: return 0;
1041: }
1042:
1043: /**
1044: * Open FCP URI
1045: *
1046: * @v parent Parent interface
1047: * @v uri URI
1048: * @ret rc Return status code
1049: */
1050: static int fcp_open ( struct interface *parent, struct uri *uri ) {
1051: struct fc_name wwn;
1052: struct scsi_lun lun;
1053: int rc;
1054:
1055: /* Parse URI */
1056: if ( ( rc = fcp_parse_uri ( uri, &wwn, &lun ) ) != 0 )
1057: return rc;
1058:
1059: /* Open FCP device */
1060: if ( ( rc = fcpdev_open ( parent, &wwn, &lun ) ) != 0 )
1061: return rc;
1062:
1063: return 0;
1064: }
1065:
1066: /** FCP URI opener */
1067: struct uri_opener fcp_uri_opener __uri_opener = {
1068: .scheme = "fcp",
1069: .open = fcp_open,
1070: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.