diff options
author | Yi Zou <yi.zou@intel.com> | 2009-11-20 17:55:24 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-04 13:01:59 -0500 |
commit | 63e27fb80c2010678681cef7b528ab8af3624fe9 (patch) | |
tree | 2ce41c886c976ead202044eb32d3e9aacc97e023 /drivers/scsi/libfc | |
parent | b84056bf68404a5fe06b452ea9790b9927e793a6 (diff) |
[SCSI] libfc: add support of receiving ELS_RLS
Upon receiving ELS_RLS, send the Link Error Status Block (LESB) back.
Signed-off-by: Yi Zou <yi.zou@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/libfc')
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 91e2ba27f7bd..35ca0e72df46 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c | |||
@@ -1098,6 +1098,78 @@ drop: | |||
1098 | } | 1098 | } |
1099 | 1099 | ||
1100 | /** | 1100 | /** |
1101 | * fc_rport_recv_rls_req() - Handle received Read Link Status request | ||
1102 | * @rdata: The remote port that sent the RLS request | ||
1103 | * @sp: The sequence that the RLS was on | ||
1104 | * @rx_fp: The PRLI request frame | ||
1105 | * | ||
1106 | * Locking Note: The rport lock is expected to be held before calling | ||
1107 | * this function. | ||
1108 | */ | ||
1109 | static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, | ||
1110 | struct fc_seq *sp, struct fc_frame *rx_fp) | ||
1111 | |||
1112 | { | ||
1113 | struct fc_lport *lport = rdata->local_port; | ||
1114 | struct fc_frame *fp; | ||
1115 | struct fc_exch *ep = fc_seq_exch(sp); | ||
1116 | struct fc_els_rls *rls; | ||
1117 | struct fc_els_rls_resp *rsp; | ||
1118 | struct fc_els_lesb *lesb; | ||
1119 | struct fc_seq_els_data rjt_data; | ||
1120 | struct fc_host_statistics *hst; | ||
1121 | u32 f_ctl; | ||
1122 | |||
1123 | FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n", | ||
1124 | fc_rport_state(rdata)); | ||
1125 | |||
1126 | rls = fc_frame_payload_get(rx_fp, sizeof(*rls)); | ||
1127 | if (!rls) { | ||
1128 | rjt_data.reason = ELS_RJT_PROT; | ||
1129 | rjt_data.explan = ELS_EXPL_INV_LEN; | ||
1130 | goto out_rjt; | ||
1131 | } | ||
1132 | |||
1133 | fp = fc_frame_alloc(lport, sizeof(*rsp)); | ||
1134 | if (!fp) { | ||
1135 | rjt_data.reason = ELS_RJT_UNAB; | ||
1136 | rjt_data.explan = ELS_EXPL_INSUF_RES; | ||
1137 | goto out_rjt; | ||
1138 | } | ||
1139 | |||
1140 | rsp = fc_frame_payload_get(fp, sizeof(*rsp)); | ||
1141 | memset(rsp, 0, sizeof(*rsp)); | ||
1142 | rsp->rls_cmd = ELS_LS_ACC; | ||
1143 | lesb = &rsp->rls_lesb; | ||
1144 | if (lport->tt.get_lesb) { | ||
1145 | /* get LESB from LLD if it supports it */ | ||
1146 | lport->tt.get_lesb(lport, lesb); | ||
1147 | } else { | ||
1148 | fc_get_host_stats(lport->host); | ||
1149 | hst = &lport->host_stats; | ||
1150 | lesb->lesb_link_fail = htonl(hst->link_failure_count); | ||
1151 | lesb->lesb_sync_loss = htonl(hst->loss_of_sync_count); | ||
1152 | lesb->lesb_sig_loss = htonl(hst->loss_of_signal_count); | ||
1153 | lesb->lesb_prim_err = htonl(hst->prim_seq_protocol_err_count); | ||
1154 | lesb->lesb_inv_word = htonl(hst->invalid_tx_word_count); | ||
1155 | lesb->lesb_inv_crc = htonl(hst->invalid_crc_count); | ||
1156 | } | ||
1157 | |||
1158 | sp = lport->tt.seq_start_next(sp); | ||
1159 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; | ||
1160 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
1161 | FC_TYPE_ELS, f_ctl, 0); | ||
1162 | lport->tt.seq_send(lport, sp, fp); | ||
1163 | goto out; | ||
1164 | |||
1165 | out_rjt: | ||
1166 | rjt_data.fp = NULL; | ||
1167 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | ||
1168 | out: | ||
1169 | fc_frame_free(rx_fp); | ||
1170 | } | ||
1171 | |||
1172 | /** | ||
1101 | * fc_rport_recv_els_req() - Handler for validated ELS requests | 1173 | * fc_rport_recv_els_req() - Handler for validated ELS requests |
1102 | * @lport: The local port that received the ELS request | 1174 | * @lport: The local port that received the ELS request |
1103 | * @sp: The sequence that the ELS request was on | 1175 | * @sp: The sequence that the ELS request was on |
@@ -1159,6 +1231,9 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, | |||
1159 | els_data.fp = fp; | 1231 | els_data.fp = fp; |
1160 | lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); | 1232 | lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); |
1161 | break; | 1233 | break; |
1234 | case ELS_RLS: | ||
1235 | fc_rport_recv_rls_req(rdata, sp, fp); | ||
1236 | break; | ||
1162 | default: | 1237 | default: |
1163 | fc_frame_free(fp); /* can't happen */ | 1238 | fc_frame_free(fp); /* can't happen */ |
1164 | break; | 1239 | break; |
@@ -1203,6 +1278,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
1203 | case ELS_ADISC: | 1278 | case ELS_ADISC: |
1204 | case ELS_RRQ: | 1279 | case ELS_RRQ: |
1205 | case ELS_REC: | 1280 | case ELS_REC: |
1281 | case ELS_RLS: | ||
1206 | fc_rport_recv_els_req(lport, sp, fp); | 1282 | fc_rport_recv_els_req(lport, sp, fp); |
1207 | break; | 1283 | break; |
1208 | default: | 1284 | default: |