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