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 | |
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>
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 9 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 21 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 12 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 61 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 157 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 134 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 92 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 41 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.h | 2 |
10 files changed, 308 insertions, 223 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 3f64c4b81b0c..6127635e6275 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -528,10 +528,11 @@ struct lpfc_hba { | |||
528 | struct fc_host_statistics link_stats; | 528 | struct fc_host_statistics link_stats; |
529 | 529 | ||
530 | struct list_head port_list; | 530 | struct list_head port_list; |
531 | struct lpfc_vport *pport; /* physical lpfc_vport pointer */ | 531 | struct lpfc_vport *pport; /* physical lpfc_vport pointer */ |
532 | uint16_t max_vpi; /* Maximum virtual nports */ | 532 | uint16_t max_vpi; /* Maximum virtual nports */ |
533 | #define LPFC_MAX_VPI 100 /* Max number of VPorts supported */ | 533 | #define LPFC_MAX_VPI 100 /* Max number of VPI supported */ |
534 | unsigned long *vpi_bmask; /* vpi allocation table */ | 534 | #define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */ |
535 | unsigned long *vpi_bmask; /* vpi allocation table */ | ||
535 | 536 | ||
536 | /* Data structure used by fabric iocb scheduler */ | 537 | /* Data structure used by fabric iocb scheduler */ |
537 | struct list_head fabric_iocb_list; | 538 | struct list_head fabric_iocb_list; |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 860a52c090f4..dbced066a361 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -1060,19 +1060,24 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val) | |||
1060 | static void | 1060 | static void |
1061 | lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba) | 1061 | lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba) |
1062 | { | 1062 | { |
1063 | struct lpfc_vport *vport; | 1063 | struct lpfc_vport **vports; |
1064 | struct Scsi_Host *shost; | 1064 | struct Scsi_Host *shost; |
1065 | struct lpfc_nodelist *ndlp; | 1065 | struct lpfc_nodelist *ndlp; |
1066 | int i; | ||
1066 | 1067 | ||
1067 | list_for_each_entry(vport, &phba->port_list, listentry) { | 1068 | vports = lpfc_create_vport_work_array(phba); |
1068 | shost = lpfc_shost_from_vport(vport); | 1069 | if (vports != NULL) |
1069 | spin_lock_irq(shost->host_lock); | 1070 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { |
1070 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) | 1071 | shost = lpfc_shost_from_vport(vports[i]); |
1072 | spin_lock_irq(shost->host_lock); | ||
1073 | list_for_each_entry(ndlp, &vports[i]->fc_nodes, | ||
1074 | nlp_listp) | ||
1071 | if (ndlp->rport) | 1075 | if (ndlp->rport) |
1072 | ndlp->rport->dev_loss_tmo = | 1076 | ndlp->rport->dev_loss_tmo = |
1073 | phba->cfg_devloss_tmo; | 1077 | phba->cfg_devloss_tmo; |
1074 | spin_unlock_irq(shost->host_lock); | 1078 | spin_unlock_irq(shost->host_lock); |
1075 | } | 1079 | } |
1080 | lpfc_destroy_vport_work_array(vports); | ||
1076 | } | 1081 | } |
1077 | 1082 | ||
1078 | static int | 1083 | static int |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index f9fdc862028a..6689d6f85adc 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -40,6 +40,7 @@ void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); | |||
40 | void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); | 40 | void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); |
41 | void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); | 41 | void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); |
42 | 42 | ||
43 | struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); | ||
43 | void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); | 44 | void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); |
44 | int lpfc_linkdown(struct lpfc_hba *); | 45 | int lpfc_linkdown(struct lpfc_hba *); |
45 | void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); | 46 | void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); |
@@ -117,6 +118,7 @@ void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, | |||
117 | int lpfc_els_handle_rscn(struct lpfc_vport *); | 118 | int lpfc_els_handle_rscn(struct lpfc_vport *); |
118 | void lpfc_els_flush_rscn(struct lpfc_vport *); | 119 | void lpfc_els_flush_rscn(struct lpfc_vport *); |
119 | int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t); | 120 | int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t); |
121 | void lpfc_els_flush_all_cmd(struct lpfc_hba *); | ||
120 | void lpfc_els_flush_cmd(struct lpfc_vport *); | 122 | void lpfc_els_flush_cmd(struct lpfc_vport *); |
121 | int lpfc_els_disc_adisc(struct lpfc_vport *); | 123 | int lpfc_els_disc_adisc(struct lpfc_vport *); |
122 | int lpfc_els_disc_plogi(struct lpfc_vport *); | 124 | int lpfc_els_disc_plogi(struct lpfc_vport *); |
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index edbebffa26cf..43e2e33f9a07 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c | |||
@@ -390,17 +390,19 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, | |||
390 | return 0; | 390 | return 0; |
391 | } | 391 | } |
392 | 392 | ||
393 | static struct lpfc_vport * | 393 | struct lpfc_vport * |
394 | lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) { | 394 | lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) { |
395 | |||
396 | struct lpfc_vport *vport_curr; | 395 | struct lpfc_vport *vport_curr; |
396 | unsigned long flags; | ||
397 | 397 | ||
398 | spin_lock_irqsave(&phba->hbalock, flags); | ||
398 | list_for_each_entry(vport_curr, &phba->port_list, listentry) { | 399 | list_for_each_entry(vport_curr, &phba->port_list, listentry) { |
399 | if ((vport_curr->fc_myDID) && | 400 | if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) { |
400 | (vport_curr->fc_myDID == did)) | 401 | spin_unlock_irqrestore(&phba->hbalock, flags); |
401 | return vport_curr; | 402 | return vport_curr; |
403 | } | ||
402 | } | 404 | } |
403 | 405 | spin_unlock_irqrestore(&phba->hbalock, flags); | |
404 | return NULL; | 406 | return NULL; |
405 | } | 407 | } |
406 | 408 | ||
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 68fc975d4e52..b8e048a467d2 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -2800,7 +2800,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
2800 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 2800 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
2801 | struct lpfc_hba *phba = vport->phba; | 2801 | struct lpfc_hba *phba = vport->phba; |
2802 | struct lpfc_dmabuf *pcmd; | 2802 | struct lpfc_dmabuf *pcmd; |
2803 | struct lpfc_vport *next_vport; | ||
2804 | uint32_t *lp, *datap; | 2803 | uint32_t *lp, *datap; |
2805 | IOCB_t *icmd; | 2804 | IOCB_t *icmd; |
2806 | uint32_t payload_len, length, nportid, *cmd; | 2805 | uint32_t payload_len, length, nportid, *cmd; |
@@ -2850,13 +2849,8 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
2850 | nportid = ((be32_to_cpu(nportid)) & Mask_DID); | 2849 | nportid = ((be32_to_cpu(nportid)) & Mask_DID); |
2851 | i -= sizeof(uint32_t); | 2850 | i -= sizeof(uint32_t); |
2852 | rscn_id++; | 2851 | rscn_id++; |
2853 | list_for_each_entry(next_vport, &phba->port_list, | 2852 | if (lpfc_find_vport_by_did(phba, nportid)) |
2854 | listentry) { | 2853 | hba_id++; |
2855 | if (nportid == next_vport->fc_myDID) { | ||
2856 | hba_id++; | ||
2857 | break; | ||
2858 | } | ||
2859 | } | ||
2860 | } | 2854 | } |
2861 | if (rscn_id == hba_id) { | 2855 | if (rscn_id == hba_id) { |
2862 | /* ALL NPortIDs in RSCN are on HBA */ | 2856 | /* ALL NPortIDs in RSCN are on HBA */ |
@@ -3740,6 +3734,50 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) | |||
3740 | return; | 3734 | return; |
3741 | } | 3735 | } |
3742 | 3736 | ||
3737 | void | ||
3738 | lpfc_els_flush_all_cmd(struct lpfc_hba *phba) | ||
3739 | { | ||
3740 | LIST_HEAD(completions); | ||
3741 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
3742 | struct lpfc_iocbq *tmp_iocb, *piocb; | ||
3743 | IOCB_t *cmd = NULL; | ||
3744 | |||
3745 | lpfc_fabric_abort_hba(phba); | ||
3746 | spin_lock_irq(&phba->hbalock); | ||
3747 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { | ||
3748 | cmd = &piocb->iocb; | ||
3749 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) | ||
3750 | continue; | ||
3751 | /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */ | ||
3752 | if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN || | ||
3753 | cmd->ulpCommand == CMD_QUE_RING_BUF64_CN || | ||
3754 | cmd->ulpCommand == CMD_CLOSE_XRI_CN || | ||
3755 | cmd->ulpCommand == CMD_ABORT_XRI_CN) | ||
3756 | continue; | ||
3757 | list_move_tail(&piocb->list, &completions); | ||
3758 | pring->txq_cnt--; | ||
3759 | } | ||
3760 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { | ||
3761 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) | ||
3762 | continue; | ||
3763 | lpfc_sli_issue_abort_iotag(phba, pring, piocb); | ||
3764 | } | ||
3765 | spin_unlock_irq(&phba->hbalock); | ||
3766 | while (!list_empty(&completions)) { | ||
3767 | piocb = list_get_first(&completions, struct lpfc_iocbq, list); | ||
3768 | cmd = &piocb->iocb; | ||
3769 | list_del_init(&piocb->list); | ||
3770 | if (!piocb->iocb_cmpl) | ||
3771 | lpfc_sli_release_iocbq(phba, piocb); | ||
3772 | else { | ||
3773 | cmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
3774 | cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; | ||
3775 | (piocb->iocb_cmpl) (phba, piocb, piocb); | ||
3776 | } | ||
3777 | } | ||
3778 | return; | ||
3779 | } | ||
3780 | |||
3743 | static void | 3781 | static void |
3744 | lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | 3782 | lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, |
3745 | struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) | 3783 | struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) |
@@ -4009,11 +4047,16 @@ static struct lpfc_vport * | |||
4009 | lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) | 4047 | lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) |
4010 | { | 4048 | { |
4011 | struct lpfc_vport *vport; | 4049 | struct lpfc_vport *vport; |
4050 | unsigned long flags; | ||
4012 | 4051 | ||
4052 | spin_lock_irqsave(&phba->hbalock, flags); | ||
4013 | list_for_each_entry(vport, &phba->port_list, listentry) { | 4053 | list_for_each_entry(vport, &phba->port_list, listentry) { |
4014 | if (vport->vpi == vpi) | 4054 | if (vport->vpi == vpi) { |
4055 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
4015 | return vport; | 4056 | return vport; |
4057 | } | ||
4016 | } | 4058 | } |
4059 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
4017 | return NULL; | 4060 | return NULL; |
4018 | } | 4061 | } |
4019 | 4062 | ||
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index ea27bbb81552..556d55fc9456 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -349,7 +349,8 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
349 | { | 349 | { |
350 | struct lpfc_sli_ring *pring; | 350 | struct lpfc_sli_ring *pring; |
351 | uint32_t ha_copy, status, control, work_port_events; | 351 | uint32_t ha_copy, status, control, work_port_events; |
352 | struct lpfc_vport *vport; | 352 | struct lpfc_vport **vports; |
353 | int i; | ||
353 | 354 | ||
354 | spin_lock_irq(&phba->hbalock); | 355 | spin_lock_irq(&phba->hbalock); |
355 | ha_copy = phba->work_ha; | 356 | ha_copy = phba->work_ha; |
@@ -364,48 +365,31 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
364 | 365 | ||
365 | if (ha_copy & HA_LATT) | 366 | if (ha_copy & HA_LATT) |
366 | lpfc_handle_latt(phba); | 367 | lpfc_handle_latt(phba); |
367 | 368 | vports = lpfc_create_vport_work_array(phba); | |
368 | spin_lock_irq(&phba->hbalock); | 369 | if (vports != NULL) |
369 | list_for_each_entry(vport, &phba->port_list, listentry) { | 370 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { |
370 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 371 | work_port_events = vports[i]->work_port_events; |
371 | 372 | if (work_port_events & WORKER_DISC_TMO) | |
372 | if (!scsi_host_get(shost)) { | 373 | lpfc_disc_timeout_handler(vports[i]); |
373 | continue; | 374 | if (work_port_events & WORKER_ELS_TMO) |
375 | lpfc_els_timeout_handler(vports[i]); | ||
376 | if (work_port_events & WORKER_HB_TMO) | ||
377 | lpfc_hb_timeout_handler(phba); | ||
378 | if (work_port_events & WORKER_MBOX_TMO) | ||
379 | lpfc_mbox_timeout_handler(phba); | ||
380 | if (work_port_events & WORKER_FABRIC_BLOCK_TMO) | ||
381 | lpfc_unblock_fabric_iocbs(phba); | ||
382 | if (work_port_events & WORKER_FDMI_TMO) | ||
383 | lpfc_fdmi_timeout_handler(vports[i]); | ||
384 | if (work_port_events & WORKER_RAMP_DOWN_QUEUE) | ||
385 | lpfc_ramp_down_queue_handler(phba); | ||
386 | if (work_port_events & WORKER_RAMP_UP_QUEUE) | ||
387 | lpfc_ramp_up_queue_handler(phba); | ||
388 | spin_lock_irq(&vports[i]->work_port_lock); | ||
389 | vports[i]->work_port_events &= ~work_port_events; | ||
390 | spin_unlock_irq(&vports[i]->work_port_lock); | ||
374 | } | 391 | } |
375 | spin_unlock_irq(&phba->hbalock); | 392 | lpfc_destroy_vport_work_array(vports); |
376 | work_port_events = vport->work_port_events; | ||
377 | |||
378 | if (work_port_events & WORKER_DISC_TMO) | ||
379 | lpfc_disc_timeout_handler(vport); | ||
380 | |||
381 | if (work_port_events & WORKER_ELS_TMO) | ||
382 | lpfc_els_timeout_handler(vport); | ||
383 | |||
384 | if (work_port_events & WORKER_HB_TMO) | ||
385 | lpfc_hb_timeout_handler(phba); | ||
386 | |||
387 | if (work_port_events & WORKER_MBOX_TMO) | ||
388 | lpfc_mbox_timeout_handler(phba); | ||
389 | |||
390 | if (work_port_events & WORKER_FABRIC_BLOCK_TMO) | ||
391 | lpfc_unblock_fabric_iocbs(phba); | ||
392 | |||
393 | if (work_port_events & WORKER_FDMI_TMO) | ||
394 | lpfc_fdmi_timeout_handler(vport); | ||
395 | |||
396 | if (work_port_events & WORKER_RAMP_DOWN_QUEUE) | ||
397 | lpfc_ramp_down_queue_handler(phba); | ||
398 | |||
399 | if (work_port_events & WORKER_RAMP_UP_QUEUE) | ||
400 | lpfc_ramp_up_queue_handler(phba); | ||
401 | |||
402 | spin_lock_irq(&vport->work_port_lock); | ||
403 | vport->work_port_events &= ~work_port_events; | ||
404 | spin_unlock_irq(&vport->work_port_lock); | ||
405 | scsi_host_put(shost); | ||
406 | spin_lock_irq(&phba->hbalock); | ||
407 | } | ||
408 | spin_unlock_irq(&phba->hbalock); | ||
409 | 393 | ||
410 | pring = &phba->sli.ring[LPFC_ELS_RING]; | 394 | pring = &phba->sli.ring[LPFC_ELS_RING]; |
411 | status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); | 395 | status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); |
@@ -448,32 +432,22 @@ static int | |||
448 | check_work_wait_done(struct lpfc_hba *phba) | 432 | check_work_wait_done(struct lpfc_hba *phba) |
449 | { | 433 | { |
450 | struct lpfc_vport *vport; | 434 | struct lpfc_vport *vport; |
451 | struct lpfc_sli_ring *pring; | 435 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; |
452 | int rc = 0; | 436 | int rc = 0; |
453 | 437 | ||
454 | spin_lock_irq(&phba->hbalock); | 438 | spin_lock_irq(&phba->hbalock); |
455 | list_for_each_entry(vport, &phba->port_list, listentry) { | 439 | list_for_each_entry(vport, &phba->port_list, listentry) { |
456 | if (vport->work_port_events) { | 440 | if (vport->work_port_events) { |
457 | rc = 1; | 441 | rc = 1; |
458 | goto exit; | 442 | break; |
459 | } | 443 | } |
460 | } | 444 | } |
461 | 445 | if (rc || phba->work_ha || (!list_empty(&phba->work_list)) || | |
462 | if (phba->work_ha || (!list_empty(&phba->work_list)) || | 446 | kthread_should_stop() || pring->flag & LPFC_DEFERRED_RING_EVENT) { |
463 | kthread_should_stop()) { | ||
464 | rc = 1; | ||
465 | goto exit; | ||
466 | } | ||
467 | |||
468 | pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
469 | if (pring->flag & LPFC_DEFERRED_RING_EVENT) | ||
470 | rc = 1; | 447 | rc = 1; |
471 | exit: | ||
472 | if (rc) | ||
473 | phba->work_found++; | 448 | phba->work_found++; |
474 | else | 449 | } else |
475 | phba->work_found = 0; | 450 | phba->work_found = 0; |
476 | |||
477 | spin_unlock_irq(&phba->hbalock); | 451 | spin_unlock_irq(&phba->hbalock); |
478 | return rc; | 452 | return rc; |
479 | } | 453 | } |
@@ -601,7 +575,6 @@ lpfc_linkdown_port(struct lpfc_vport *vport) | |||
601 | 575 | ||
602 | /* free any ndlp's on unused list */ | 576 | /* free any ndlp's on unused list */ |
603 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) | 577 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) |
604 | /* free any ndlp's in unused state */ | ||
605 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | 578 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) |
606 | lpfc_drop_node(vport, ndlp); | 579 | lpfc_drop_node(vport, ndlp); |
607 | 580 | ||
@@ -614,8 +587,9 @@ lpfc_linkdown(struct lpfc_hba *phba) | |||
614 | { | 587 | { |
615 | struct lpfc_vport *vport = phba->pport; | 588 | struct lpfc_vport *vport = phba->pport; |
616 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 589 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
617 | struct lpfc_vport *port_iterator; | 590 | struct lpfc_vport **vports; |
618 | LPFC_MBOXQ_t *mb; | 591 | LPFC_MBOXQ_t *mb; |
592 | int i; | ||
619 | 593 | ||
620 | if (phba->link_state == LPFC_LINK_DOWN) { | 594 | if (phba->link_state == LPFC_LINK_DOWN) { |
621 | return 0; | 595 | return 0; |
@@ -626,13 +600,13 @@ lpfc_linkdown(struct lpfc_hba *phba) | |||
626 | phba->pport->fc_flag &= ~FC_LBIT; | 600 | phba->pport->fc_flag &= ~FC_LBIT; |
627 | } | 601 | } |
628 | spin_unlock_irq(&phba->hbalock); | 602 | spin_unlock_irq(&phba->hbalock); |
629 | 603 | vports = lpfc_create_vport_work_array(phba); | |
630 | list_for_each_entry(port_iterator, &phba->port_list, listentry) { | 604 | if (vports != NULL) |
631 | 605 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { | |
632 | /* Issue a LINK DOWN event to all nodes */ | 606 | /* Issue a LINK DOWN event to all nodes */ |
633 | lpfc_linkdown_port(port_iterator); | 607 | lpfc_linkdown_port(vports[i]); |
634 | } | 608 | } |
635 | 609 | lpfc_destroy_vport_work_array(vports); | |
636 | /* Clean up any firmware default rpi's */ | 610 | /* Clean up any firmware default rpi's */ |
637 | mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | 611 | mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); |
638 | if (mb) { | 612 | if (mb) { |
@@ -733,7 +707,8 @@ lpfc_linkup_port(struct lpfc_vport *vport) | |||
733 | static int | 707 | static int |
734 | lpfc_linkup(struct lpfc_hba *phba) | 708 | lpfc_linkup(struct lpfc_hba *phba) |
735 | { | 709 | { |
736 | struct lpfc_vport *vport; | 710 | struct lpfc_vport **vports; |
711 | int i; | ||
737 | 712 | ||
738 | phba->link_state = LPFC_LINK_UP; | 713 | phba->link_state = LPFC_LINK_UP; |
739 | 714 | ||
@@ -741,9 +716,11 @@ lpfc_linkup(struct lpfc_hba *phba) | |||
741 | clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); | 716 | clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); |
742 | del_timer_sync(&phba->fabric_block_timer); | 717 | del_timer_sync(&phba->fabric_block_timer); |
743 | 718 | ||
744 | list_for_each_entry(vport, &phba->port_list, listentry) { | 719 | vports = lpfc_create_vport_work_array(phba); |
745 | lpfc_linkup_port(vport); | 720 | if (vports != NULL) |
746 | } | 721 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) |
722 | lpfc_linkup_port(vports[i]); | ||
723 | lpfc_destroy_vport_work_array(vports); | ||
747 | if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) | 724 | if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) |
748 | lpfc_issue_clear_la(phba, phba->pport); | 725 | lpfc_issue_clear_la(phba, phba->pport); |
749 | 726 | ||
@@ -1298,15 +1275,15 @@ void | |||
1298 | lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | 1275 | lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) |
1299 | { | 1276 | { |
1300 | struct lpfc_vport *vport = pmb->vport; | 1277 | struct lpfc_vport *vport = pmb->vport; |
1301 | struct lpfc_vport *next_vport; | ||
1302 | MAILBOX_t *mb = &pmb->mb; | 1278 | MAILBOX_t *mb = &pmb->mb; |
1303 | struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); | 1279 | struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); |
1304 | struct lpfc_nodelist *ndlp; | 1280 | struct lpfc_nodelist *ndlp; |
1305 | ndlp = (struct lpfc_nodelist *) pmb->context2; | 1281 | struct lpfc_vport **vports; |
1282 | int i; | ||
1306 | 1283 | ||
1284 | ndlp = (struct lpfc_nodelist *) pmb->context2; | ||
1307 | pmb->context1 = NULL; | 1285 | pmb->context1 = NULL; |
1308 | pmb->context2 = NULL; | 1286 | pmb->context2 = NULL; |
1309 | |||
1310 | if (mb->mbxStatus) { | 1287 | if (mb->mbxStatus) { |
1311 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1288 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1312 | kfree(mp); | 1289 | kfree(mp); |
@@ -1337,21 +1314,27 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1337 | lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ | 1314 | lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ |
1338 | 1315 | ||
1339 | if (vport->port_state == LPFC_FABRIC_CFG_LINK) { | 1316 | if (vport->port_state == LPFC_FABRIC_CFG_LINK) { |
1340 | list_for_each_entry(next_vport, &phba->port_list, listentry) { | 1317 | vports = lpfc_create_vport_work_array(phba); |
1341 | if (next_vport->port_type == LPFC_PHYSICAL_PORT) | 1318 | if (vports != NULL) |
1342 | continue; | 1319 | for(i = 0; |
1343 | 1320 | i < LPFC_MAX_VPORTS && vports[i] != NULL; | |
1344 | if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) | 1321 | i++) { |
1345 | lpfc_initial_fdisc(next_vport); | 1322 | if (vports[i]->port_type == LPFC_PHYSICAL_PORT) |
1346 | else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { | 1323 | continue; |
1347 | lpfc_vport_set_state(vport, | 1324 | if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) |
1348 | FC_VPORT_NO_FABRIC_SUPP); | 1325 | lpfc_initial_fdisc(vports[i]); |
1349 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | 1326 | else if (phba->sli3_options & |
1350 | "%d (%d):0259 No NPIV Fabric " | 1327 | LPFC_SLI3_NPIV_ENABLED) { |
1351 | "support\n", | 1328 | lpfc_vport_set_state(vports[i], |
1352 | phba->brd_no, vport->vpi); | 1329 | FC_VPORT_NO_FABRIC_SUPP); |
1330 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||
1331 | "%d (%d):0259 No NPIV " | ||
1332 | "Fabric support\n", | ||
1333 | phba->brd_no, | ||
1334 | vports[i]->vpi); | ||
1335 | } | ||
1353 | } | 1336 | } |
1354 | } | 1337 | lpfc_destroy_vport_work_array(vports); |
1355 | lpfc_do_scr_ns_plogi(phba, vport); | 1338 | lpfc_do_scr_ns_plogi(phba, vport); |
1356 | } | 1339 | } |
1357 | 1340 | ||
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 | ||
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 8f45bbc42126..0284ded96bad 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -119,42 +119,40 @@ lpfc_rampup_queue_depth(struct lpfc_hba *phba, | |||
119 | void | 119 | void |
120 | lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) | 120 | lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) |
121 | { | 121 | { |
122 | struct lpfc_vport *vport; | 122 | struct lpfc_vport **vports; |
123 | struct Scsi_Host *host; | 123 | struct Scsi_Host *shost; |
124 | struct scsi_device *sdev; | 124 | struct scsi_device *sdev; |
125 | unsigned long new_queue_depth; | 125 | unsigned long new_queue_depth; |
126 | unsigned long num_rsrc_err, num_cmd_success; | 126 | unsigned long num_rsrc_err, num_cmd_success; |
127 | int i; | ||
127 | 128 | ||
128 | num_rsrc_err = atomic_read(&phba->num_rsrc_err); | 129 | num_rsrc_err = atomic_read(&phba->num_rsrc_err); |
129 | num_cmd_success = atomic_read(&phba->num_cmd_success); | 130 | num_cmd_success = atomic_read(&phba->num_cmd_success); |
130 | 131 | ||
131 | spin_lock_irq(&phba->hbalock); | 132 | vports = lpfc_create_vport_work_array(phba); |
132 | list_for_each_entry(vport, &phba->port_list, listentry) { | 133 | if (vports != NULL) |
133 | host = lpfc_shost_from_vport(vport); | 134 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { |
134 | if (!scsi_host_get(host)) | 135 | shost = lpfc_shost_from_vport(vports[i]); |
135 | continue; | 136 | shost_for_each_device(sdev, shost) { |
136 | |||
137 | spin_unlock_irq(&phba->hbalock); | ||
138 | |||
139 | shost_for_each_device(sdev, host) { | ||
140 | new_queue_depth = sdev->queue_depth * num_rsrc_err / | ||
141 | (num_rsrc_err + num_cmd_success); | ||
142 | if (!new_queue_depth) | ||
143 | new_queue_depth = sdev->queue_depth - 1; | ||
144 | else | ||
145 | new_queue_depth = | 137 | new_queue_depth = |
146 | sdev->queue_depth - new_queue_depth; | 138 | sdev->queue_depth * num_rsrc_err / |
147 | 139 | (num_rsrc_err + num_cmd_success); | |
148 | if (sdev->ordered_tags) | 140 | if (!new_queue_depth) |
149 | scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, | 141 | new_queue_depth = sdev->queue_depth - 1; |
150 | new_queue_depth); | 142 | else |
151 | else | 143 | new_queue_depth = sdev->queue_depth - |
152 | scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, | 144 | new_queue_depth; |
153 | new_queue_depth); | 145 | if (sdev->ordered_tags) |
146 | scsi_adjust_queue_depth(sdev, | ||
147 | MSG_ORDERED_TAG, | ||
148 | new_queue_depth); | ||
149 | else | ||
150 | scsi_adjust_queue_depth(sdev, | ||
151 | MSG_SIMPLE_TAG, | ||
152 | new_queue_depth); | ||
153 | } | ||
154 | } | 154 | } |
155 | spin_lock_irq(&phba->hbalock); | 155 | lpfc_destroy_vport_work_array(vports); |
156 | scsi_host_put(host); | ||
157 | } | ||
158 | spin_unlock_irq(&phba->hbalock); | 156 | spin_unlock_irq(&phba->hbalock); |
159 | atomic_set(&phba->num_rsrc_err, 0); | 157 | atomic_set(&phba->num_rsrc_err, 0); |
160 | atomic_set(&phba->num_cmd_success, 0); | 158 | atomic_set(&phba->num_cmd_success, 0); |
@@ -163,29 +161,27 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) | |||
163 | void | 161 | void |
164 | lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) | 162 | lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) |
165 | { | 163 | { |
166 | struct lpfc_vport *vport; | 164 | struct lpfc_vport **vports; |
167 | struct Scsi_Host *host; | 165 | struct Scsi_Host *shost; |
168 | struct scsi_device *sdev; | 166 | struct scsi_device *sdev; |
169 | 167 | int i; | |
170 | spin_lock_irq(&phba->hbalock); | 168 | |
171 | list_for_each_entry(vport, &phba->port_list, listentry) { | 169 | vports = lpfc_create_vport_work_array(phba); |
172 | host = lpfc_shost_from_vport(vport); | 170 | if (vports != NULL) |
173 | if (!scsi_host_get(host)) | 171 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { |
174 | continue; | 172 | shost = lpfc_shost_from_vport(vports[i]); |
175 | 173 | shost_for_each_device(sdev, shost) { | |
176 | spin_unlock_irq(&phba->hbalock); | 174 | if (sdev->ordered_tags) |
177 | shost_for_each_device(sdev, host) { | 175 | scsi_adjust_queue_depth(sdev, |
178 | if (sdev->ordered_tags) | 176 | MSG_ORDERED_TAG, |
179 | scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, | 177 | sdev->queue_depth+1); |
180 | sdev->queue_depth+1); | 178 | else |
181 | else | 179 | scsi_adjust_queue_depth(sdev, |
182 | scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, | 180 | MSG_SIMPLE_TAG, |
183 | sdev->queue_depth+1); | 181 | sdev->queue_depth+1); |
182 | } | ||
184 | } | 183 | } |
185 | spin_lock_irq(&phba->hbalock); | 184 | lpfc_destroy_vport_work_array(vports); |
186 | scsi_host_put(host); | ||
187 | } | ||
188 | spin_unlock_irq(&phba->hbalock); | ||
189 | atomic_set(&phba->num_rsrc_err, 0); | 185 | atomic_set(&phba->num_rsrc_err, 0); |
190 | atomic_set(&phba->num_cmd_success, 0); | 186 | atomic_set(&phba->num_cmd_success, 0); |
191 | } | 187 | } |
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index c5918a643014..e066855b0783 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c | |||
@@ -176,16 +176,21 @@ static int | |||
176 | lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) | 176 | lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) |
177 | { | 177 | { |
178 | struct lpfc_vport *vport; | 178 | struct lpfc_vport *vport; |
179 | unsigned long flags; | ||
179 | 180 | ||
181 | spin_lock_irqsave(&phba->hbalock, flags); | ||
180 | list_for_each_entry(vport, &phba->port_list, listentry) { | 182 | list_for_each_entry(vport, &phba->port_list, listentry) { |
181 | if (vport == new_vport) | 183 | if (vport == new_vport) |
182 | continue; | 184 | continue; |
183 | /* If they match, return not unique */ | 185 | /* If they match, return not unique */ |
184 | if (memcmp(&vport->fc_sparam.portName, | 186 | if (memcmp(&vport->fc_sparam.portName, |
185 | &new_vport->fc_sparam.portName, | 187 | &new_vport->fc_sparam.portName, |
186 | sizeof(struct lpfc_name)) == 0) | 188 | sizeof(struct lpfc_name)) == 0) { |
189 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
187 | return 0; | 190 | return 0; |
191 | } | ||
188 | } | 192 | } |
193 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
189 | return 1; | 194 | return 1; |
190 | } | 195 | } |
191 | 196 | ||
@@ -524,6 +529,36 @@ out: | |||
524 | return rc; | 529 | return rc; |
525 | } | 530 | } |
526 | 531 | ||
527 | |||
528 | EXPORT_SYMBOL(lpfc_vport_create); | 532 | EXPORT_SYMBOL(lpfc_vport_create); |
529 | EXPORT_SYMBOL(lpfc_vport_delete); | 533 | EXPORT_SYMBOL(lpfc_vport_delete); |
534 | |||
535 | struct lpfc_vport ** | ||
536 | lpfc_create_vport_work_array(struct lpfc_hba *phba) | ||
537 | { | ||
538 | struct lpfc_vport *port_iterator; | ||
539 | struct lpfc_vport **vports; | ||
540 | int index = 0; | ||
541 | vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *), | ||
542 | GFP_KERNEL); | ||
543 | if (vports == NULL) | ||
544 | return NULL; | ||
545 | spin_lock_irq(&phba->hbalock); | ||
546 | list_for_each_entry(port_iterator, &phba->port_list, listentry) { | ||
547 | if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) | ||
548 | continue; | ||
549 | vports[index++] = port_iterator; | ||
550 | } | ||
551 | spin_unlock_irq(&phba->hbalock); | ||
552 | return vports; | ||
553 | } | ||
554 | |||
555 | void | ||
556 | lpfc_destroy_vport_work_array(struct lpfc_vport **vports) | ||
557 | { | ||
558 | int i; | ||
559 | if (vports == NULL) | ||
560 | return; | ||
561 | for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++) | ||
562 | scsi_host_put(lpfc_shost_from_vport(vports[i])); | ||
563 | kfree(vports); | ||
564 | } | ||
diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h index f223550f8cba..91da17751a37 100644 --- a/drivers/scsi/lpfc/lpfc_vport.h +++ b/drivers/scsi/lpfc/lpfc_vport.h | |||
@@ -88,6 +88,8 @@ int lpfc_vport_create(struct fc_vport *, bool); | |||
88 | int lpfc_vport_delete(struct fc_vport *); | 88 | int lpfc_vport_delete(struct fc_vport *); |
89 | int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *); | 89 | int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *); |
90 | int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint); | 90 | int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint); |
91 | struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *); | ||
92 | void lpfc_destroy_vport_work_array(struct lpfc_vport **); | ||
91 | 93 | ||
92 | /* | 94 | /* |
93 | * queuecommand VPORT-specific return codes. Specified in the host byte code. | 95 | * queuecommand VPORT-specific return codes. Specified in the host byte code. |