aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/fcoe
diff options
context:
space:
mode:
authorBhanu Prakash Gollapudi <bprakash@broadcom.com>2011-05-16 19:45:24 -0400
committerJames Bottomley <jbottomley@parallels.com>2011-05-24 12:36:17 -0400
commitc051ad2e57e379e07e4ec28b2a54eeb0d04c5d59 (patch)
treee210bbdc9319229f36988448b65139b698d132af /drivers/scsi/fcoe
parent4f788dce0baf44295a8d9708d3f124587158c061 (diff)
[SCSI] libfcoe: Incorrect CVL handling for NPIV ports
Host doesnt handle CVL to NPIV instantiated ports correctly. - As per FC-BB-5 Rev 2 CVLs with no VN_Port descriptors shall be treated as implicit logout of ALL vn_ports. - CVL for NPIV ports should be handled before physical port even if descriptor for physical port appears before NPIV ports Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <jbottomley@parallels.com>
Diffstat (limited to 'drivers/scsi/fcoe')
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c133
1 files changed, 90 insertions, 43 deletions
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 229e4af5508a..c74c4b8e71ef 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -1173,7 +1173,9 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
1173 struct fc_lport *lport = fip->lp; 1173 struct fc_lport *lport = fip->lp;
1174 struct fc_lport *vn_port = NULL; 1174 struct fc_lport *vn_port = NULL;
1175 u32 desc_mask; 1175 u32 desc_mask;
1176 int is_vn_port = 0; 1176 int num_vlink_desc;
1177 int reset_phys_port = 0;
1178 struct fip_vn_desc **vlink_desc_arr = NULL;
1177 1179
1178 LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); 1180 LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
1179 1181
@@ -1183,70 +1185,73 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
1183 /* 1185 /*
1184 * mask of required descriptors. Validating each one clears its bit. 1186 * mask of required descriptors. Validating each one clears its bit.
1185 */ 1187 */
1186 desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | BIT(FIP_DT_VN_ID); 1188 desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME);
1187 1189
1188 rlen = ntohs(fh->fip_dl_len) * FIP_BPW; 1190 rlen = ntohs(fh->fip_dl_len) * FIP_BPW;
1189 desc = (struct fip_desc *)(fh + 1); 1191 desc = (struct fip_desc *)(fh + 1);
1192
1193 /*
1194 * Actually need to subtract 'sizeof(*mp) - sizeof(*wp)' from 'rlen'
1195 * before determining max Vx_Port descriptor but a buggy FCF could have
1196 * omited either or both MAC Address and Name Identifier descriptors
1197 */
1198 num_vlink_desc = rlen / sizeof(*vp);
1199 if (num_vlink_desc)
1200 vlink_desc_arr = kmalloc(sizeof(vp) * num_vlink_desc,
1201 GFP_ATOMIC);
1202 if (!vlink_desc_arr)
1203 return;
1204 num_vlink_desc = 0;
1205
1190 while (rlen >= sizeof(*desc)) { 1206 while (rlen >= sizeof(*desc)) {
1191 dlen = desc->fip_dlen * FIP_BPW; 1207 dlen = desc->fip_dlen * FIP_BPW;
1192 if (dlen > rlen) 1208 if (dlen > rlen)
1193 return; 1209 goto err;
1194 /* Drop CVL if there are duplicate critical descriptors */ 1210 /* Drop CVL if there are duplicate critical descriptors */
1195 if ((desc->fip_dtype < 32) && 1211 if ((desc->fip_dtype < 32) &&
1212 (desc->fip_dtype != FIP_DT_VN_ID) &&
1196 !(desc_mask & 1U << desc->fip_dtype)) { 1213 !(desc_mask & 1U << desc->fip_dtype)) {
1197 LIBFCOE_FIP_DBG(fip, "Duplicate Critical " 1214 LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
1198 "Descriptors in FIP CVL\n"); 1215 "Descriptors in FIP CVL\n");
1199 return; 1216 goto err;
1200 } 1217 }
1201 switch (desc->fip_dtype) { 1218 switch (desc->fip_dtype) {
1202 case FIP_DT_MAC: 1219 case FIP_DT_MAC:
1203 mp = (struct fip_mac_desc *)desc; 1220 mp = (struct fip_mac_desc *)desc;
1204 if (dlen < sizeof(*mp)) 1221 if (dlen < sizeof(*mp))
1205 return; 1222 goto err;
1206 if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac)) 1223 if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac))
1207 return; 1224 goto err;
1208 desc_mask &= ~BIT(FIP_DT_MAC); 1225 desc_mask &= ~BIT(FIP_DT_MAC);
1209 break; 1226 break;
1210 case FIP_DT_NAME: 1227 case FIP_DT_NAME:
1211 wp = (struct fip_wwn_desc *)desc; 1228 wp = (struct fip_wwn_desc *)desc;
1212 if (dlen < sizeof(*wp)) 1229 if (dlen < sizeof(*wp))
1213 return; 1230 goto err;
1214 if (get_unaligned_be64(&wp->fd_wwn) != fcf->switch_name) 1231 if (get_unaligned_be64(&wp->fd_wwn) != fcf->switch_name)
1215 return; 1232 goto err;
1216 desc_mask &= ~BIT(FIP_DT_NAME); 1233 desc_mask &= ~BIT(FIP_DT_NAME);
1217 break; 1234 break;
1218 case FIP_DT_VN_ID: 1235 case FIP_DT_VN_ID:
1219 vp = (struct fip_vn_desc *)desc; 1236 vp = (struct fip_vn_desc *)desc;
1220 if (dlen < sizeof(*vp)) 1237 if (dlen < sizeof(*vp))
1221 return; 1238 goto err;
1222 if (compare_ether_addr(vp->fd_mac, 1239 vlink_desc_arr[num_vlink_desc++] = vp;
1223 fip->get_src_addr(lport)) == 0 && 1240 vn_port = fc_vport_id_lookup(lport,
1224 get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn && 1241 ntoh24(vp->fd_fc_id));
1225 ntoh24(vp->fd_fc_id) == lport->port_id) { 1242 if (vn_port && (vn_port == lport)) {
1226 desc_mask &= ~BIT(FIP_DT_VN_ID); 1243 mutex_lock(&fip->ctlr_mutex);
1227 break; 1244 per_cpu_ptr(lport->dev_stats,
1245 get_cpu())->VLinkFailureCount++;
1246 put_cpu();
1247 fcoe_ctlr_reset(fip);
1248 mutex_unlock(&fip->ctlr_mutex);
1228 } 1249 }
1229 /* check if clr_vlink is for NPIV port */
1230 mutex_lock(&lport->lp_mutex);
1231 list_for_each_entry(vn_port, &lport->vports, list) {
1232 if (compare_ether_addr(vp->fd_mac,
1233 fip->get_src_addr(vn_port)) == 0 &&
1234 (get_unaligned_be64(&vp->fd_wwpn)
1235 == vn_port->wwpn) &&
1236 (ntoh24(vp->fd_fc_id) ==
1237 fc_host_port_id(vn_port->host))) {
1238 desc_mask &= ~BIT(FIP_DT_VN_ID);
1239 is_vn_port = 1;
1240 break;
1241 }
1242 }
1243 mutex_unlock(&lport->lp_mutex);
1244
1245 break; 1250 break;
1246 default: 1251 default:
1247 /* standard says ignore unknown descriptors >= 128 */ 1252 /* standard says ignore unknown descriptors >= 128 */
1248 if (desc->fip_dtype < FIP_DT_VENDOR_BASE) 1253 if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
1249 return; 1254 goto err;
1250 break; 1255 break;
1251 } 1256 }
1252 desc = (struct fip_desc *)((char *)desc + dlen); 1257 desc = (struct fip_desc *)((char *)desc + dlen);
@@ -1256,26 +1261,68 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
1256 /* 1261 /*
1257 * reset only if all required descriptors were present and valid. 1262 * reset only if all required descriptors were present and valid.
1258 */ 1263 */
1259 if (desc_mask) { 1264 if (desc_mask)
1260 LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n", 1265 LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n",
1261 desc_mask); 1266 desc_mask);
1267 else if (!num_vlink_desc) {
1268 LIBFCOE_FIP_DBG(fip, "CVL: no Vx_Port descriptor found\n");
1269 /*
1270 * No Vx_Port description. Clear all NPIV ports,
1271 * followed by physical port
1272 */
1273 mutex_lock(&lport->lp_mutex);
1274 list_for_each_entry(vn_port, &lport->vports, list)
1275 fc_lport_reset(vn_port);
1276 mutex_unlock(&lport->lp_mutex);
1277
1278 mutex_lock(&fip->ctlr_mutex);
1279 per_cpu_ptr(lport->dev_stats,
1280 get_cpu())->VLinkFailureCount++;
1281 put_cpu();
1282 fcoe_ctlr_reset(fip);
1283 mutex_unlock(&fip->ctlr_mutex);
1284
1285 fc_lport_reset(fip->lp);
1286 fcoe_ctlr_solicit(fip, NULL);
1262 } else { 1287 } else {
1263 LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n"); 1288 int i;
1264 1289
1265 if (is_vn_port) 1290 LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
1266 fc_lport_reset(vn_port); 1291 for (i = 0; i < num_vlink_desc; i++) {
1267 else { 1292 vp = vlink_desc_arr[i];
1268 mutex_lock(&fip->ctlr_mutex); 1293 vn_port = fc_vport_id_lookup(lport,
1269 per_cpu_ptr(lport->dev_stats, 1294 ntoh24(vp->fd_fc_id));
1270 get_cpu())->VLinkFailureCount++; 1295 if (!vn_port)
1271 put_cpu(); 1296 continue;
1272 fcoe_ctlr_reset(fip); 1297
1273 mutex_unlock(&fip->ctlr_mutex); 1298 /*
1299 * 'port_id' is already validated, check MAC address and
1300 * wwpn
1301 */
1302 if (compare_ether_addr(fip->get_src_addr(vn_port),
1303 vp->fd_mac) != 0 ||
1304 get_unaligned_be64(&vp->fd_wwpn) !=
1305 vn_port->wwpn)
1306 continue;
1307
1308 if (vn_port == lport)
1309 /*
1310 * Physical port, defer processing till all
1311 * listed NPIV ports are cleared
1312 */
1313 reset_phys_port = 1;
1314 else /* NPIV port */
1315 fc_lport_reset(vn_port);
1316 }
1274 1317
1318 if (reset_phys_port) {
1275 fc_lport_reset(fip->lp); 1319 fc_lport_reset(fip->lp);
1276 fcoe_ctlr_solicit(fip, NULL); 1320 fcoe_ctlr_solicit(fip, NULL);
1277 } 1321 }
1278 } 1322 }
1323
1324err:
1325 kfree(vlink_desc_arr);
1279} 1326}
1280 1327
1281/** 1328/**