diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-08-02 11:09:51 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-08-01 13:18:23 -0400 |
commit | 549e55cd2a1b83ea45ac17fb6c309654a3d371a4 (patch) | |
tree | 0abf10a28b177e129932c62b3b94994ce4f3aadb /drivers/scsi/lpfc/lpfc_init.c | |
parent | a58cbd5212fff2d4bba0bf58e778f02069597294 (diff) |
[SCSI] lpfc 8.2.2 : Fix locking around HBA's port_list
Cleans up a lot of bad behaviors that have been in this area a while
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_init.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 134 |
1 files changed, 75 insertions, 59 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 07bd0dcdf0d6..484070c82974 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -437,16 +437,18 @@ lpfc_config_port_post(struct lpfc_hba *phba) | |||
437 | int | 437 | int |
438 | lpfc_hba_down_prep(struct lpfc_hba *phba) | 438 | lpfc_hba_down_prep(struct lpfc_hba *phba) |
439 | { | 439 | { |
440 | struct lpfc_vport *vport = phba->pport; | 440 | struct lpfc_vport **vports; |
441 | int i; | ||
441 | 442 | ||
442 | /* Disable interrupts */ | 443 | /* Disable interrupts */ |
443 | writel(0, phba->HCregaddr); | 444 | writel(0, phba->HCregaddr); |
444 | readl(phba->HCregaddr); /* flush */ | 445 | readl(phba->HCregaddr); /* flush */ |
445 | 446 | ||
446 | list_for_each_entry(vport, &phba->port_list, listentry) { | 447 | vports = lpfc_create_vport_work_array(phba); |
447 | lpfc_cleanup_discovery_resources(vport); | 448 | if (vports != NULL) |
448 | } | 449 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) |
449 | 450 | lpfc_cleanup_discovery_resources(vports[i]); | |
451 | lpfc_destroy_vport_work_array(vports); | ||
450 | return 0; | 452 | return 0; |
451 | } | 453 | } |
452 | 454 | ||
@@ -615,9 +617,10 @@ lpfc_handle_eratt(struct lpfc_hba *phba) | |||
615 | struct lpfc_vport *vport = phba->pport; | 617 | struct lpfc_vport *vport = phba->pport; |
616 | struct lpfc_sli *psli = &phba->sli; | 618 | struct lpfc_sli *psli = &phba->sli; |
617 | struct lpfc_sli_ring *pring; | 619 | struct lpfc_sli_ring *pring; |
618 | struct lpfc_vport *port_iterator; | 620 | struct lpfc_vport **vports; |
619 | uint32_t event_data; | 621 | uint32_t event_data; |
620 | struct Scsi_Host *shost; | 622 | struct Scsi_Host *shost; |
623 | int i; | ||
621 | 624 | ||
622 | /* If the pci channel is offline, ignore possible errors, | 625 | /* If the pci channel is offline, ignore possible errors, |
623 | * since we cannot communicate with the pci card anyway. */ | 626 | * since we cannot communicate with the pci card anyway. */ |
@@ -632,14 +635,17 @@ lpfc_handle_eratt(struct lpfc_hba *phba) | |||
632 | "Data: x%x x%x x%x\n", | 635 | "Data: x%x x%x x%x\n", |
633 | phba->brd_no, phba->work_hs, | 636 | phba->brd_no, phba->work_hs, |
634 | phba->work_status[0], phba->work_status[1]); | 637 | phba->work_status[0], phba->work_status[1]); |
635 | list_for_each_entry(port_iterator, &phba->port_list, | 638 | vports = lpfc_create_vport_work_array(phba); |
636 | listentry) { | 639 | if (vports != NULL) |
637 | shost = lpfc_shost_from_vport(port_iterator); | 640 | for(i = 0; |
638 | 641 | i < LPFC_MAX_VPORTS && vports[i] != NULL; | |
639 | spin_lock_irq(shost->host_lock); | 642 | i++){ |
640 | port_iterator->fc_flag |= FC_ESTABLISH_LINK; | 643 | shost = lpfc_shost_from_vport(vports[i]); |
641 | spin_unlock_irq(shost->host_lock); | 644 | spin_lock_irq(shost->host_lock); |
642 | } | 645 | vports[i]->fc_flag |= FC_ESTABLISH_LINK; |
646 | spin_unlock_irq(shost->host_lock); | ||
647 | } | ||
648 | lpfc_destroy_vport_work_array(vports); | ||
643 | spin_lock_irq(&phba->hbalock); | 649 | spin_lock_irq(&phba->hbalock); |
644 | psli->sli_flag &= ~LPFC_SLI2_ACTIVE; | 650 | psli->sli_flag &= ~LPFC_SLI2_ACTIVE; |
645 | spin_unlock_irq(&phba->hbalock); | 651 | spin_unlock_irq(&phba->hbalock); |
@@ -708,7 +714,6 @@ lpfc_handle_latt(struct lpfc_hba *phba) | |||
708 | { | 714 | { |
709 | struct lpfc_vport *vport = phba->pport; | 715 | struct lpfc_vport *vport = phba->pport; |
710 | struct lpfc_sli *psli = &phba->sli; | 716 | struct lpfc_sli *psli = &phba->sli; |
711 | struct lpfc_vport *port_iterator; | ||
712 | LPFC_MBOXQ_t *pmb; | 717 | LPFC_MBOXQ_t *pmb; |
713 | volatile uint32_t control; | 718 | volatile uint32_t control; |
714 | struct lpfc_dmabuf *mp; | 719 | struct lpfc_dmabuf *mp; |
@@ -729,8 +734,7 @@ lpfc_handle_latt(struct lpfc_hba *phba) | |||
729 | rc = -EIO; | 734 | rc = -EIO; |
730 | 735 | ||
731 | /* Cleanup any outstanding ELS commands */ | 736 | /* Cleanup any outstanding ELS commands */ |
732 | list_for_each_entry(port_iterator, &phba->port_list, listentry) | 737 | lpfc_els_flush_all_cmd(phba); |
733 | lpfc_els_flush_cmd(port_iterator); | ||
734 | 738 | ||
735 | psli->slistat.link_event++; | 739 | psli->slistat.link_event++; |
736 | lpfc_read_la(phba, pmb, mp); | 740 | lpfc_read_la(phba, pmb, mp); |
@@ -1313,22 +1317,26 @@ static void | |||
1313 | lpfc_establish_link_tmo(unsigned long ptr) | 1317 | lpfc_establish_link_tmo(unsigned long ptr) |
1314 | { | 1318 | { |
1315 | struct lpfc_hba *phba = (struct lpfc_hba *) ptr; | 1319 | struct lpfc_hba *phba = (struct lpfc_hba *) ptr; |
1316 | struct lpfc_vport *vport = phba->pport; | 1320 | struct lpfc_vport **vports; |
1317 | unsigned long iflag; | 1321 | unsigned long iflag; |
1322 | int i; | ||
1318 | 1323 | ||
1319 | /* Re-establishing Link, timer expired */ | 1324 | /* Re-establishing Link, timer expired */ |
1320 | lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, | 1325 | lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, |
1321 | "%d:1300 Re-establishing Link, timer expired " | 1326 | "%d:1300 Re-establishing Link, timer expired " |
1322 | "Data: x%x x%x\n", | 1327 | "Data: x%x x%x\n", |
1323 | phba->brd_no, vport->fc_flag, | 1328 | phba->brd_no, phba->pport->fc_flag, |
1324 | vport->port_state); | 1329 | phba->pport->port_state); |
1325 | list_for_each_entry(vport, &phba->port_list, listentry) { | 1330 | vports = lpfc_create_vport_work_array(phba); |
1326 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1331 | if (vports != NULL) |
1327 | 1332 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { | |
1328 | spin_lock_irqsave(shost->host_lock, iflag); | 1333 | struct Scsi_Host *shost; |
1329 | vport->fc_flag &= ~FC_ESTABLISH_LINK; | 1334 | shost = lpfc_shost_from_vport(vports[i]); |
1330 | spin_unlock_irqrestore(shost->host_lock, iflag); | 1335 | spin_lock_irqsave(shost->host_lock, iflag); |
1331 | } | 1336 | vports[i]->fc_flag &= ~FC_ESTABLISH_LINK; |
1337 | spin_unlock_irqrestore(shost->host_lock, iflag); | ||
1338 | } | ||
1339 | lpfc_destroy_vport_work_array(vports); | ||
1332 | } | 1340 | } |
1333 | 1341 | ||
1334 | void | 1342 | void |
@@ -1343,12 +1351,16 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport) | |||
1343 | static void | 1351 | static void |
1344 | lpfc_stop_phba_timers(struct lpfc_hba *phba) | 1352 | lpfc_stop_phba_timers(struct lpfc_hba *phba) |
1345 | { | 1353 | { |
1346 | struct lpfc_vport *vport; | 1354 | struct lpfc_vport **vports; |
1355 | int i; | ||
1347 | 1356 | ||
1348 | del_timer_sync(&phba->fcp_poll_timer); | 1357 | del_timer_sync(&phba->fcp_poll_timer); |
1349 | del_timer_sync(&phba->fc_estabtmo); | 1358 | del_timer_sync(&phba->fc_estabtmo); |
1350 | list_for_each_entry(vport, &phba->port_list, listentry) | 1359 | vports = lpfc_create_vport_work_array(phba); |
1351 | lpfc_stop_vport_timers(vport); | 1360 | if (vports != NULL) |
1361 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) | ||
1362 | lpfc_stop_vport_timers(vports[i]); | ||
1363 | lpfc_destroy_vport_work_array(vports); | ||
1352 | del_timer_sync(&phba->sli.mbox_tmo); | 1364 | del_timer_sync(&phba->sli.mbox_tmo); |
1353 | del_timer_sync(&phba->fabric_block_timer); | 1365 | del_timer_sync(&phba->fabric_block_timer); |
1354 | phba->hb_outstanding = 0; | 1366 | phba->hb_outstanding = 0; |
@@ -1360,6 +1372,8 @@ int | |||
1360 | lpfc_online(struct lpfc_hba *phba) | 1372 | lpfc_online(struct lpfc_hba *phba) |
1361 | { | 1373 | { |
1362 | struct lpfc_vport *vport = phba->pport; | 1374 | struct lpfc_vport *vport = phba->pport; |
1375 | struct lpfc_vport **vports; | ||
1376 | int i; | ||
1363 | 1377 | ||
1364 | if (!phba) | 1378 | if (!phba) |
1365 | return 0; | 1379 | return 0; |
@@ -1383,14 +1397,18 @@ lpfc_online(struct lpfc_hba *phba) | |||
1383 | return 1; | 1397 | return 1; |
1384 | } | 1398 | } |
1385 | 1399 | ||
1386 | list_for_each_entry(vport, &phba->port_list, listentry) { | 1400 | vports = lpfc_create_vport_work_array(phba); |
1387 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1401 | if (vports != NULL) |
1388 | spin_lock_irq(shost->host_lock); | 1402 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { |
1389 | vport->fc_flag &= ~FC_OFFLINE_MODE; | 1403 | struct Scsi_Host *shost; |
1390 | if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) | 1404 | shost = lpfc_shost_from_vport(vports[i]); |
1391 | vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; | 1405 | spin_lock_irq(shost->host_lock); |
1392 | spin_unlock_irq(shost->host_lock); | 1406 | vports[i]->fc_flag &= ~FC_OFFLINE_MODE; |
1393 | } | 1407 | if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) |
1408 | vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; | ||
1409 | spin_unlock_irq(shost->host_lock); | ||
1410 | } | ||
1411 | lpfc_destroy_vport_work_array(vports); | ||
1394 | 1412 | ||
1395 | lpfc_unblock_mgmt_io(phba); | 1413 | lpfc_unblock_mgmt_io(phba); |
1396 | return 0; | 1414 | return 0; |
@@ -1440,39 +1458,35 @@ lpfc_offline_prep(struct lpfc_hba * phba) | |||
1440 | void | 1458 | void |
1441 | lpfc_offline(struct lpfc_hba *phba) | 1459 | lpfc_offline(struct lpfc_hba *phba) |
1442 | { | 1460 | { |
1443 | struct lpfc_vport *vport = phba->pport; | 1461 | struct Scsi_Host *shost; |
1444 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1462 | struct lpfc_vport **vports; |
1445 | struct lpfc_vport *port_iterator; | 1463 | int i; |
1446 | 1464 | ||
1447 | if (vport->fc_flag & FC_OFFLINE_MODE) | 1465 | if (phba->pport->fc_flag & FC_OFFLINE_MODE) |
1448 | return; | 1466 | return; |
1449 | 1467 | ||
1450 | /* stop all timers associated with this hba */ | 1468 | /* stop all timers associated with this hba */ |
1451 | lpfc_stop_phba_timers(phba); | 1469 | lpfc_stop_phba_timers(phba); |
1452 | list_for_each_entry(port_iterator, &phba->port_list, listentry) { | ||
1453 | port_iterator->work_port_events = 0; | ||
1454 | } | ||
1455 | |||
1456 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, | 1470 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, |
1457 | "%d:0460 Bring Adapter offline\n", | 1471 | "%d:0460 Bring Adapter offline\n", |
1458 | phba->brd_no); | 1472 | phba->brd_no); |
1459 | |||
1460 | /* Bring down the SLI Layer and cleanup. The HBA is offline | 1473 | /* Bring down the SLI Layer and cleanup. The HBA is offline |
1461 | now. */ | 1474 | now. */ |
1462 | lpfc_sli_hba_down(phba); | 1475 | lpfc_sli_hba_down(phba); |
1463 | spin_lock_irq(&phba->hbalock); | 1476 | spin_lock_irq(&phba->hbalock); |
1464 | phba->work_ha = 0; | 1477 | phba->work_ha = 0; |
1465 | vport->fc_flag |= FC_OFFLINE_MODE; | ||
1466 | spin_unlock_irq(&phba->hbalock); | 1478 | spin_unlock_irq(&phba->hbalock); |
1467 | list_for_each_entry(port_iterator, &phba->port_list, listentry) { | 1479 | vports = lpfc_create_vport_work_array(phba); |
1468 | shost = lpfc_shost_from_vport(port_iterator); | 1480 | if (vports != NULL) |
1469 | 1481 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { | |
1470 | lpfc_cleanup(port_iterator); | 1482 | shost = lpfc_shost_from_vport(vports[i]); |
1471 | spin_lock_irq(shost->host_lock); | 1483 | lpfc_cleanup(vports[i]); |
1472 | vport->work_port_events = 0; | 1484 | spin_lock_irq(shost->host_lock); |
1473 | vport->fc_flag |= FC_OFFLINE_MODE; | 1485 | vports[i]->work_port_events = 0; |
1474 | spin_unlock_irq(shost->host_lock); | 1486 | vports[i]->fc_flag |= FC_OFFLINE_MODE; |
1475 | } | 1487 | spin_unlock_irq(shost->host_lock); |
1488 | } | ||
1489 | lpfc_destroy_vport_work_array(vports); | ||
1476 | } | 1490 | } |
1477 | 1491 | ||
1478 | /****************************************************************************** | 1492 | /****************************************************************************** |
@@ -1509,7 +1523,6 @@ lpfc_scsi_free(struct lpfc_hba *phba) | |||
1509 | return 0; | 1523 | return 0; |
1510 | } | 1524 | } |
1511 | 1525 | ||
1512 | |||
1513 | struct lpfc_vport * | 1526 | struct lpfc_vport * |
1514 | lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport) | 1527 | lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport) |
1515 | { | 1528 | { |
@@ -1570,7 +1583,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport) | |||
1570 | if (error) | 1583 | if (error) |
1571 | goto out_put_shost; | 1584 | goto out_put_shost; |
1572 | 1585 | ||
1586 | spin_lock_irq(&phba->hbalock); | ||
1573 | list_add_tail(&vport->listentry, &phba->port_list); | 1587 | list_add_tail(&vport->listentry, &phba->port_list); |
1588 | spin_unlock_irq(&phba->hbalock); | ||
1574 | return vport; | 1589 | return vport; |
1575 | 1590 | ||
1576 | out_put_shost: | 1591 | out_put_shost: |
@@ -1990,8 +2005,10 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
1990 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | 2005 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; |
1991 | struct lpfc_hba *phba = vport->phba; | 2006 | struct lpfc_hba *phba = vport->phba; |
1992 | struct lpfc_vport *port_iterator; | 2007 | struct lpfc_vport *port_iterator; |
2008 | spin_lock_irq(&phba->hbalock); | ||
1993 | list_for_each_entry(port_iterator, &phba->port_list, listentry) | 2009 | list_for_each_entry(port_iterator, &phba->port_list, listentry) |
1994 | port_iterator->load_flag |= FC_UNLOADING; | 2010 | port_iterator->load_flag |= FC_UNLOADING; |
2011 | spin_unlock_irq(&phba->hbalock); | ||
1995 | 2012 | ||
1996 | kfree(vport->vname); | 2013 | kfree(vport->vname); |
1997 | lpfc_free_sysfs_attr(vport); | 2014 | lpfc_free_sysfs_attr(vport); |
@@ -2012,7 +2029,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
2012 | list_del_init(&vport->listentry); | 2029 | list_del_init(&vport->listentry); |
2013 | spin_unlock_irq(&phba->hbalock); | 2030 | spin_unlock_irq(&phba->hbalock); |
2014 | 2031 | ||
2015 | |||
2016 | lpfc_debugfs_terminate(vport); | 2032 | lpfc_debugfs_terminate(vport); |
2017 | lpfc_cleanup(vport); | 2033 | lpfc_cleanup(vport); |
2018 | 2034 | ||