| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright(c) 2008 Intel Corporation. All rights reserved. | 
 | 3 |  * | 
 | 4 |  * This program is free software; you can redistribute it and/or modify it | 
 | 5 |  * under the terms and conditions of the GNU General Public License, | 
 | 6 |  * version 2, as published by the Free Software Foundation. | 
 | 7 |  * | 
 | 8 |  * This program is distributed in the hope it will be useful, but WITHOUT | 
 | 9 |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
 | 10 |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | 
 | 11 |  * more details. | 
 | 12 |  * | 
 | 13 |  * You should have received a copy of the GNU General Public License along with | 
 | 14 |  * this program; if not, write to the Free Software Foundation, Inc., | 
 | 15 |  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 
 | 16 |  * | 
 | 17 |  * Maintained at www.Open-FCoE.org | 
 | 18 |  */ | 
 | 19 |  | 
 | 20 | /* | 
 | 21 |  * Provide interface to send ELS/CT FC frames | 
 | 22 |  */ | 
 | 23 |  | 
 | 24 | #include <asm/unaligned.h> | 
 | 25 | #include <scsi/fc/fc_gs.h> | 
 | 26 | #include <scsi/fc/fc_ns.h> | 
 | 27 | #include <scsi/fc/fc_els.h> | 
 | 28 | #include <scsi/libfc.h> | 
 | 29 | #include <scsi/fc_encode.h> | 
 | 30 |  | 
| Robert Love | 3a3b42b | 2009-11-03 11:47:39 -0800 | [diff] [blame] | 31 | /** | 
 | 32 |  * fc_elsct_send() - Send an ELS or CT frame | 
 | 33 |  * @lport:	The local port to send the frame on | 
 | 34 |  * @did:	The destination ID for the frame | 
 | 35 |  * @fp:		The frame to be sent | 
 | 36 |  * @op:		The operational code | 
 | 37 |  * @resp:	The callback routine when the response is received | 
 | 38 |  * @arg:	The argument to pass to the response callback routine | 
 | 39 |  * @timer_msec: The timeout period for the frame (in msecs) | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 40 |  */ | 
| Robert Love | 3a3b42b | 2009-11-03 11:47:39 -0800 | [diff] [blame] | 41 | struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did, | 
 | 42 | 			     struct fc_frame *fp, unsigned int op, | 
 | 43 | 			     void (*resp)(struct fc_seq *, | 
 | 44 | 					  struct fc_frame *, | 
 | 45 | 					  void *), | 
 | 46 | 			     void *arg, u32 timer_msec) | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 47 | { | 
 | 48 | 	enum fc_rctl r_ctl; | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 49 | 	enum fc_fh_type fh_type; | 
 | 50 | 	int rc; | 
 | 51 |  | 
 | 52 | 	/* ELS requests */ | 
 | 53 | 	if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) | 
| Joe Eykholt | a46f327 | 2009-08-25 14:00:55 -0700 | [diff] [blame] | 54 | 		rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); | 
 | 55 | 	else { | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 56 | 		/* CT requests */ | 
| Joe Eykholt | 2ab7e1e | 2009-08-25 14:03:58 -0700 | [diff] [blame] | 57 | 		rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type); | 
| Joe Eykholt | a46f327 | 2009-08-25 14:00:55 -0700 | [diff] [blame] | 58 | 		did = FC_FID_DIR_SERV; | 
 | 59 | 	} | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 60 |  | 
| Chris Leech | 8f550f9 | 2009-10-21 16:28:09 -0700 | [diff] [blame] | 61 | 	if (rc) { | 
 | 62 | 		fc_frame_free(fp); | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 63 | 		return NULL; | 
| Chris Leech | 8f550f9 | 2009-10-21 16:28:09 -0700 | [diff] [blame] | 64 | 	} | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 65 |  | 
 | 66 | 	fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type, | 
 | 67 | 		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); | 
 | 68 |  | 
 | 69 | 	return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); | 
 | 70 | } | 
| Chris Leech | 11b5618 | 2009-11-03 11:46:29 -0800 | [diff] [blame] | 71 | EXPORT_SYMBOL(fc_elsct_send); | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 72 |  | 
| Robert Love | 3a3b42b | 2009-11-03 11:47:39 -0800 | [diff] [blame] | 73 | /** | 
 | 74 |  * fc_elsct_init() - Initialize the ELS/CT layer | 
 | 75 |  * @lport: The local port to initialize the ELS/CT layer for | 
 | 76 |  */ | 
| Robert Love | 42e9a92 | 2008-12-09 15:10:17 -0800 | [diff] [blame] | 77 | int fc_elsct_init(struct fc_lport *lport) | 
 | 78 | { | 
 | 79 | 	if (!lport->tt.elsct_send) | 
 | 80 | 		lport->tt.elsct_send = fc_elsct_send; | 
 | 81 |  | 
 | 82 | 	return 0; | 
 | 83 | } | 
 | 84 | EXPORT_SYMBOL(fc_elsct_init); | 
| Joe Eykholt | f657d29 | 2009-08-25 14:03:21 -0700 | [diff] [blame] | 85 |  | 
 | 86 | /** | 
| Robert Love | 3a3b42b | 2009-11-03 11:47:39 -0800 | [diff] [blame] | 87 |  * fc_els_resp_type() - Return a string describing the ELS response | 
 | 88 |  * @fp: The frame pointer or possible error code | 
| Joe Eykholt | f657d29 | 2009-08-25 14:03:21 -0700 | [diff] [blame] | 89 |  */ | 
 | 90 | const char *fc_els_resp_type(struct fc_frame *fp) | 
 | 91 | { | 
 | 92 | 	const char *msg; | 
| Joe Eykholt | 52a6690 | 2009-11-03 11:49:00 -0800 | [diff] [blame] | 93 | 	struct fc_frame_header *fh; | 
 | 94 | 	struct fc_ct_hdr *ct; | 
 | 95 |  | 
| Joe Eykholt | f657d29 | 2009-08-25 14:03:21 -0700 | [diff] [blame] | 96 | 	if (IS_ERR(fp)) { | 
 | 97 | 		switch (-PTR_ERR(fp)) { | 
 | 98 | 		case FC_NO_ERR: | 
 | 99 | 			msg = "response no error"; | 
 | 100 | 			break; | 
 | 101 | 		case FC_EX_TIMEOUT: | 
 | 102 | 			msg = "response timeout"; | 
 | 103 | 			break; | 
 | 104 | 		case FC_EX_CLOSED: | 
 | 105 | 			msg = "response closed"; | 
 | 106 | 			break; | 
 | 107 | 		default: | 
 | 108 | 			msg = "response unknown error"; | 
 | 109 | 			break; | 
 | 110 | 		} | 
 | 111 | 	} else { | 
| Joe Eykholt | 52a6690 | 2009-11-03 11:49:00 -0800 | [diff] [blame] | 112 | 		fh = fc_frame_header_get(fp); | 
 | 113 | 		switch (fh->fh_type) { | 
 | 114 | 		case FC_TYPE_ELS: | 
 | 115 | 			switch (fc_frame_payload_op(fp)) { | 
 | 116 | 			case ELS_LS_ACC: | 
 | 117 | 				msg = "accept"; | 
 | 118 | 				break; | 
 | 119 | 			case ELS_LS_RJT: | 
 | 120 | 				msg = "reject"; | 
 | 121 | 				break; | 
 | 122 | 			default: | 
 | 123 | 				msg = "response unknown ELS"; | 
 | 124 | 				break; | 
 | 125 | 			} | 
| Joe Eykholt | f657d29 | 2009-08-25 14:03:21 -0700 | [diff] [blame] | 126 | 			break; | 
| Joe Eykholt | 52a6690 | 2009-11-03 11:49:00 -0800 | [diff] [blame] | 127 | 		case FC_TYPE_CT: | 
 | 128 | 			ct = fc_frame_payload_get(fp, sizeof(*ct)); | 
 | 129 | 			if (ct) { | 
 | 130 | 				switch (ntohs(ct->ct_cmd)) { | 
 | 131 | 				case FC_FS_ACC: | 
 | 132 | 					msg = "CT accept"; | 
 | 133 | 					break; | 
 | 134 | 				case FC_FS_RJT: | 
 | 135 | 					msg = "CT reject"; | 
 | 136 | 					break; | 
 | 137 | 				default: | 
 | 138 | 					msg = "response unknown CT"; | 
 | 139 | 					break; | 
 | 140 | 				} | 
 | 141 | 			} else { | 
 | 142 | 				msg = "short CT response"; | 
 | 143 | 			} | 
| Joe Eykholt | f657d29 | 2009-08-25 14:03:21 -0700 | [diff] [blame] | 144 | 			break; | 
 | 145 | 		default: | 
| Joe Eykholt | 52a6690 | 2009-11-03 11:49:00 -0800 | [diff] [blame] | 146 | 			msg = "response not ELS or CT"; | 
| Joe Eykholt | f657d29 | 2009-08-25 14:03:21 -0700 | [diff] [blame] | 147 | 			break; | 
 | 148 | 		} | 
 | 149 | 	} | 
 | 150 | 	return msg; | 
 | 151 | } |