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