aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
diff options
context:
space:
mode:
authorBhanu Prakash Gollapudi <bprakash@broadcom.com>2011-05-27 14:47:27 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-06-29 12:02:09 -0400
commitd36b3279e157641c345b12eddb3db78fb42da80f (patch)
treea4b1a9a40930728bde81b569f67f2f708384b25d /drivers/scsi/bnx2fc/bnx2fc_fcoe.c
parentb5a95fe7ef464a67fab6ff870aa740739e788f90 (diff)
[SCSI] bnx2fc: Fix kernel panic when deleting NPIV ports
Deleting NPIV port causes a kernel panic when the NPIV port is in the same zone as the physical port and shares the same LUN. This happens due to the fact that vport destroy and unsolicited ELS are scheduled to run on the same workqueue, and vport destroy destroys the lport and the unsolicited ELS tries to access the invalid lport. This patch fixes this issue by maintaining a list of valid lports and verifying if the lport is valid or not before accessing it. Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/bnx2fc/bnx2fc_fcoe.c')
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 8f894e410b5d..5c8c59e5bade 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -1228,6 +1228,7 @@ static int bnx2fc_interface_setup(struct bnx2fc_hba *hba,
1228 hba->ctlr.get_src_addr = bnx2fc_get_src_mac; 1228 hba->ctlr.get_src_addr = bnx2fc_get_src_mac;
1229 set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done); 1229 set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done);
1230 1230
1231 INIT_LIST_HEAD(&hba->vports);
1231 rc = bnx2fc_netdev_setup(hba); 1232 rc = bnx2fc_netdev_setup(hba);
1232 if (rc) 1233 if (rc)
1233 goto setup_err; 1234 goto setup_err;
@@ -1264,8 +1265,15 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
1264 struct fcoe_port *port; 1265 struct fcoe_port *port;
1265 struct Scsi_Host *shost; 1266 struct Scsi_Host *shost;
1266 struct fc_vport *vport = dev_to_vport(parent); 1267 struct fc_vport *vport = dev_to_vport(parent);
1268 struct bnx2fc_lport *blport;
1267 int rc = 0; 1269 int rc = 0;
1268 1270
1271 blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL);
1272 if (!blport) {
1273 BNX2FC_HBA_DBG(hba->ctlr.lp, "Unable to alloc bnx2fc_lport\n");
1274 return NULL;
1275 }
1276
1269 /* Allocate Scsi_Host structure */ 1277 /* Allocate Scsi_Host structure */
1270 if (!npiv) 1278 if (!npiv)
1271 lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); 1279 lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port));
@@ -1274,7 +1282,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
1274 1282
1275 if (!lport) { 1283 if (!lport) {
1276 printk(KERN_ERR PFX "could not allocate scsi host structure\n"); 1284 printk(KERN_ERR PFX "could not allocate scsi host structure\n");
1277 return NULL; 1285 goto free_blport;
1278 } 1286 }
1279 shost = lport->host; 1287 shost = lport->host;
1280 port = lport_priv(lport); 1288 port = lport_priv(lport);
@@ -1330,12 +1338,20 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
1330 } 1338 }
1331 1339
1332 bnx2fc_interface_get(hba); 1340 bnx2fc_interface_get(hba);
1341
1342 spin_lock_bh(&hba->hba_lock);
1343 blport->lport = lport;
1344 list_add_tail(&blport->list, &hba->vports);
1345 spin_unlock_bh(&hba->hba_lock);
1346
1333 return lport; 1347 return lport;
1334 1348
1335shost_err: 1349shost_err:
1336 scsi_remove_host(shost); 1350 scsi_remove_host(shost);
1337lp_config_err: 1351lp_config_err:
1338 scsi_host_put(lport->host); 1352 scsi_host_put(lport->host);
1353free_blport:
1354 kfree(blport);
1339 return NULL; 1355 return NULL;
1340} 1356}
1341 1357
@@ -1351,6 +1367,7 @@ static void bnx2fc_if_destroy(struct fc_lport *lport)
1351{ 1367{
1352 struct fcoe_port *port = lport_priv(lport); 1368 struct fcoe_port *port = lport_priv(lport);
1353 struct bnx2fc_hba *hba = port->priv; 1369 struct bnx2fc_hba *hba = port->priv;
1370 struct bnx2fc_lport *blport, *tmp;
1354 1371
1355 BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n"); 1372 BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n");
1356 /* Stop the transmit retry timer */ 1373 /* Stop the transmit retry timer */
@@ -1375,6 +1392,15 @@ static void bnx2fc_if_destroy(struct fc_lport *lport)
1375 /* Free memory used by statistical counters */ 1392 /* Free memory used by statistical counters */
1376 fc_lport_free_stats(lport); 1393 fc_lport_free_stats(lport);
1377 1394
1395 spin_lock_bh(&hba->hba_lock);
1396 list_for_each_entry_safe(blport, tmp, &hba->vports, list) {
1397 if (blport->lport == lport) {
1398 list_del(&blport->list);
1399 kfree(blport);
1400 }
1401 }
1402 spin_unlock_bh(&hba->hba_lock);
1403
1378 /* Release Scsi_Host */ 1404 /* Release Scsi_Host */
1379 scsi_host_put(lport->host); 1405 scsi_host_put(lport->host);
1380 1406