diff options
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 23 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 20 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 94 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 7 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 67 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 30 |
7 files changed, 207 insertions, 36 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 420238cc794e..114bc5a81171 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
| @@ -1838,26 +1838,33 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) | |||
| 1838 | 1838 | ||
| 1839 | qla24xx_disable_vp(vha); | 1839 | qla24xx_disable_vp(vha); |
| 1840 | 1840 | ||
| 1841 | vha->flags.delete_progress = 1; | ||
| 1842 | |||
| 1841 | fc_remove_host(vha->host); | 1843 | fc_remove_host(vha->host); |
| 1842 | 1844 | ||
| 1843 | scsi_remove_host(vha->host); | 1845 | scsi_remove_host(vha->host); |
| 1844 | 1846 | ||
| 1845 | qla2x00_free_fcports(vha); | 1847 | if (vha->timer_active) { |
| 1848 | qla2x00_vp_stop_timer(vha); | ||
| 1849 | DEBUG15(printk(KERN_INFO "scsi(%ld): timer for the vport[%d]" | ||
| 1850 | " = %p has stopped\n", vha->host_no, vha->vp_idx, vha)); | ||
| 1851 | } | ||
| 1846 | 1852 | ||
| 1847 | qla24xx_deallocate_vp_id(vha); | 1853 | qla24xx_deallocate_vp_id(vha); |
| 1848 | 1854 | ||
| 1855 | /* No pending activities shall be there on the vha now */ | ||
| 1856 | DEBUG(msleep(random32()%10)); /* Just to see if something falls on | ||
| 1857 | * the net we have placed below */ | ||
| 1858 | |||
| 1859 | BUG_ON(atomic_read(&vha->vref_count)); | ||
| 1860 | |||
| 1861 | qla2x00_free_fcports(vha); | ||
| 1862 | |||
| 1849 | mutex_lock(&ha->vport_lock); | 1863 | mutex_lock(&ha->vport_lock); |
| 1850 | ha->cur_vport_count--; | 1864 | ha->cur_vport_count--; |
| 1851 | clear_bit(vha->vp_idx, ha->vp_idx_map); | 1865 | clear_bit(vha->vp_idx, ha->vp_idx_map); |
| 1852 | mutex_unlock(&ha->vport_lock); | 1866 | mutex_unlock(&ha->vport_lock); |
| 1853 | 1867 | ||
| 1854 | if (vha->timer_active) { | ||
| 1855 | qla2x00_vp_stop_timer(vha); | ||
| 1856 | DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p " | ||
| 1857 | "has stopped\n", | ||
| 1858 | vha->host_no, vha->vp_idx, vha)); | ||
| 1859 | } | ||
| 1860 | |||
| 1861 | if (vha->req->id && !ha->flags.cpu_affinity_enabled) { | 1868 | if (vha->req->id && !ha->flags.cpu_affinity_enabled) { |
| 1862 | if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) | 1869 | if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) |
| 1863 | qla_printk(KERN_WARNING, ha, | 1870 | qla_printk(KERN_WARNING, ha, |
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 6cfc28a25eb3..b74e6b5743dc 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h | |||
| @@ -29,8 +29,6 @@ | |||
| 29 | /* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace messages */ | 29 | /* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace messages */ |
| 30 | /* #define QL_DEBUG_LEVEL_18 */ /* Output T10 CRC trace messages */ | 30 | /* #define QL_DEBUG_LEVEL_18 */ /* Output T10 CRC trace messages */ |
| 31 | 31 | ||
| 32 | /* #define QL_PRINTK_BUF */ /* Captures printk to buffer */ | ||
| 33 | |||
| 34 | /* | 32 | /* |
| 35 | * Macros use for debugging the driver. | 33 | * Macros use for debugging the driver. |
| 36 | */ | 34 | */ |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3a432ea0c7a3..d2a4e1530708 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
| @@ -2641,6 +2641,7 @@ struct qla_hw_data { | |||
| 2641 | #define MBX_UPDATE_FLASH_ACTIVE 3 | 2641 | #define MBX_UPDATE_FLASH_ACTIVE 3 |
| 2642 | 2642 | ||
| 2643 | struct mutex vport_lock; /* Virtual port synchronization */ | 2643 | struct mutex vport_lock; /* Virtual port synchronization */ |
| 2644 | spinlock_t vport_slock; /* order is hardware_lock, then vport_slock */ | ||
| 2644 | struct completion mbx_cmd_comp; /* Serialize mbx access */ | 2645 | struct completion mbx_cmd_comp; /* Serialize mbx access */ |
| 2645 | struct completion mbx_intr_comp; /* Used for completion notification */ | 2646 | struct completion mbx_intr_comp; /* Used for completion notification */ |
| 2646 | struct completion dcbx_comp; /* For set port config notification */ | 2647 | struct completion dcbx_comp; /* For set port config notification */ |
| @@ -2828,6 +2829,7 @@ typedef struct scsi_qla_host { | |||
| 2828 | uint32_t management_server_logged_in :1; | 2829 | uint32_t management_server_logged_in :1; |
| 2829 | uint32_t process_response_queue :1; | 2830 | uint32_t process_response_queue :1; |
| 2830 | uint32_t difdix_supported:1; | 2831 | uint32_t difdix_supported:1; |
| 2832 | uint32_t delete_progress:1; | ||
| 2831 | } flags; | 2833 | } flags; |
| 2832 | 2834 | ||
| 2833 | atomic_t loop_state; | 2835 | atomic_t loop_state; |
| @@ -2922,6 +2924,8 @@ typedef struct scsi_qla_host { | |||
| 2922 | struct req_que *req; | 2924 | struct req_que *req; |
| 2923 | int fw_heartbeat_counter; | 2925 | int fw_heartbeat_counter; |
| 2924 | int seconds_since_last_heartbeat; | 2926 | int seconds_since_last_heartbeat; |
| 2927 | |||
| 2928 | atomic_t vref_count; | ||
| 2925 | } scsi_qla_host_t; | 2929 | } scsi_qla_host_t; |
| 2926 | 2930 | ||
| 2927 | /* | 2931 | /* |
| @@ -2932,6 +2936,22 @@ typedef struct scsi_qla_host { | |||
| 2932 | test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \ | 2936 | test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \ |
| 2933 | atomic_read(&ha->loop_state) == LOOP_DOWN) | 2937 | atomic_read(&ha->loop_state) == LOOP_DOWN) |
| 2934 | 2938 | ||
| 2939 | #define QLA_VHA_MARK_BUSY(__vha, __bail) do { \ | ||
| 2940 | atomic_inc(&__vha->vref_count); \ | ||
| 2941 | mb(); \ | ||
| 2942 | if (__vha->flags.delete_progress) { \ | ||
| 2943 | atomic_dec(&__vha->vref_count); \ | ||
| 2944 | __bail = 1; \ | ||
| 2945 | } else { \ | ||
| 2946 | __bail = 0; \ | ||
| 2947 | } \ | ||
| 2948 | } while (0) | ||
| 2949 | |||
| 2950 | #define QLA_VHA_MARK_NOT_BUSY(__vha) do { \ | ||
| 2951 | atomic_dec(&__vha->vref_count); \ | ||
| 2952 | } while (0) | ||
| 2953 | |||
| 2954 | |||
| 2935 | #define qla_printk(level, ha, format, arg...) \ | 2955 | #define qla_printk(level, ha, format, arg...) \ |
| 2936 | dev_printk(level , &((ha)->pdev->dev) , format , ## arg) | 2956 | dev_printk(level , &((ha)->pdev->dev) , format , ## arg) |
| 2937 | 2957 | ||
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d863ed2619b5..9c383baebe27 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
| @@ -69,21 +69,29 @@ qla2x00_ctx_sp_free(srb_t *sp) | |||
| 69 | { | 69 | { |
| 70 | struct srb_ctx *ctx = sp->ctx; | 70 | struct srb_ctx *ctx = sp->ctx; |
| 71 | struct srb_iocb *iocb = ctx->u.iocb_cmd; | 71 | struct srb_iocb *iocb = ctx->u.iocb_cmd; |
| 72 | struct scsi_qla_host *vha = sp->fcport->vha; | ||
| 72 | 73 | ||
| 73 | del_timer_sync(&iocb->timer); | 74 | del_timer_sync(&iocb->timer); |
| 74 | kfree(iocb); | 75 | kfree(iocb); |
| 75 | kfree(ctx); | 76 | kfree(ctx); |
| 76 | mempool_free(sp, sp->fcport->vha->hw->srb_mempool); | 77 | mempool_free(sp, sp->fcport->vha->hw->srb_mempool); |
| 78 | |||
| 79 | QLA_VHA_MARK_NOT_BUSY(vha); | ||
| 77 | } | 80 | } |
| 78 | 81 | ||
| 79 | inline srb_t * | 82 | inline srb_t * |
| 80 | qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, | 83 | qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, |
| 81 | unsigned long tmo) | 84 | unsigned long tmo) |
| 82 | { | 85 | { |
| 83 | srb_t *sp; | 86 | srb_t *sp = NULL; |
| 84 | struct qla_hw_data *ha = vha->hw; | 87 | struct qla_hw_data *ha = vha->hw; |
| 85 | struct srb_ctx *ctx; | 88 | struct srb_ctx *ctx; |
| 86 | struct srb_iocb *iocb; | 89 | struct srb_iocb *iocb; |
| 90 | uint8_t bail; | ||
| 91 | |||
| 92 | QLA_VHA_MARK_BUSY(vha, bail); | ||
| 93 | if (bail) | ||
| 94 | return NULL; | ||
| 87 | 95 | ||
| 88 | sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); | 96 | sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); |
| 89 | if (!sp) | 97 | if (!sp) |
| @@ -116,6 +124,8 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, | |||
| 116 | iocb->timer.function = qla2x00_ctx_sp_timeout; | 124 | iocb->timer.function = qla2x00_ctx_sp_timeout; |
| 117 | add_timer(&iocb->timer); | 125 | add_timer(&iocb->timer); |
| 118 | done: | 126 | done: |
| 127 | if (!sp) | ||
| 128 | QLA_VHA_MARK_NOT_BUSY(vha); | ||
| 119 | return sp; | 129 | return sp; |
| 120 | } | 130 | } |
| 121 | 131 | ||
| @@ -1777,11 +1787,15 @@ qla2x00_init_rings(scsi_qla_host_t *vha) | |||
| 1777 | qla2x00_init_response_q_entries(rsp); | 1787 | qla2x00_init_response_q_entries(rsp); |
| 1778 | } | 1788 | } |
| 1779 | 1789 | ||
| 1790 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 1780 | /* Clear RSCN queue. */ | 1791 | /* Clear RSCN queue. */ |
| 1781 | list_for_each_entry(vp, &ha->vp_list, list) { | 1792 | list_for_each_entry(vp, &ha->vp_list, list) { |
| 1782 | vp->rscn_in_ptr = 0; | 1793 | vp->rscn_in_ptr = 0; |
| 1783 | vp->rscn_out_ptr = 0; | 1794 | vp->rscn_out_ptr = 0; |
| 1784 | } | 1795 | } |
| 1796 | |||
| 1797 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 1798 | |||
| 1785 | ha->isp_ops->config_rings(vha); | 1799 | ha->isp_ops->config_rings(vha); |
| 1786 | 1800 | ||
| 1787 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 1801 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
| @@ -3218,12 +3232,17 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, | |||
| 3218 | /* Bypass virtual ports of the same host. */ | 3232 | /* Bypass virtual ports of the same host. */ |
| 3219 | found = 0; | 3233 | found = 0; |
| 3220 | if (ha->num_vhosts) { | 3234 | if (ha->num_vhosts) { |
| 3235 | unsigned long flags; | ||
| 3236 | |||
| 3237 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 3221 | list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { | 3238 | list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { |
| 3222 | if (new_fcport->d_id.b24 == vp->d_id.b24) { | 3239 | if (new_fcport->d_id.b24 == vp->d_id.b24) { |
| 3223 | found = 1; | 3240 | found = 1; |
| 3224 | break; | 3241 | break; |
| 3225 | } | 3242 | } |
| 3226 | } | 3243 | } |
| 3244 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 3245 | |||
| 3227 | if (found) | 3246 | if (found) |
| 3228 | continue; | 3247 | continue; |
| 3229 | } | 3248 | } |
| @@ -3343,6 +3362,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) | |||
| 3343 | struct qla_hw_data *ha = vha->hw; | 3362 | struct qla_hw_data *ha = vha->hw; |
| 3344 | struct scsi_qla_host *vp; | 3363 | struct scsi_qla_host *vp; |
| 3345 | struct scsi_qla_host *tvp; | 3364 | struct scsi_qla_host *tvp; |
| 3365 | unsigned long flags = 0; | ||
| 3346 | 3366 | ||
| 3347 | rval = QLA_SUCCESS; | 3367 | rval = QLA_SUCCESS; |
| 3348 | 3368 | ||
| @@ -3367,6 +3387,8 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) | |||
| 3367 | /* Check for loop ID being already in use. */ | 3387 | /* Check for loop ID being already in use. */ |
| 3368 | found = 0; | 3388 | found = 0; |
| 3369 | fcport = NULL; | 3389 | fcport = NULL; |
| 3390 | |||
| 3391 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 3370 | list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { | 3392 | list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { |
| 3371 | list_for_each_entry(fcport, &vp->vp_fcports, list) { | 3393 | list_for_each_entry(fcport, &vp->vp_fcports, list) { |
| 3372 | if (fcport->loop_id == dev->loop_id && | 3394 | if (fcport->loop_id == dev->loop_id && |
| @@ -3379,6 +3401,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) | |||
| 3379 | if (found) | 3401 | if (found) |
| 3380 | break; | 3402 | break; |
| 3381 | } | 3403 | } |
| 3404 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 3382 | 3405 | ||
| 3383 | /* If not in use then it is free to use. */ | 3406 | /* If not in use then it is free to use. */ |
| 3384 | if (!found) { | 3407 | if (!found) { |
| @@ -3791,14 +3814,27 @@ void | |||
| 3791 | qla2x00_update_fcports(scsi_qla_host_t *base_vha) | 3814 | qla2x00_update_fcports(scsi_qla_host_t *base_vha) |
| 3792 | { | 3815 | { |
| 3793 | fc_port_t *fcport; | 3816 | fc_port_t *fcport; |
| 3794 | struct scsi_qla_host *tvp, *vha; | 3817 | struct scsi_qla_host *vha; |
| 3818 | struct qla_hw_data *ha = base_vha->hw; | ||
| 3819 | unsigned long flags; | ||
| 3795 | 3820 | ||
| 3821 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 3796 | /* Go with deferred removal of rport references. */ | 3822 | /* Go with deferred removal of rport references. */ |
| 3797 | list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list) | 3823 | list_for_each_entry(vha, &base_vha->hw->vp_list, list) { |
| 3798 | list_for_each_entry(fcport, &vha->vp_fcports, list) | 3824 | atomic_inc(&vha->vref_count); |
| 3825 | list_for_each_entry(fcport, &vha->vp_fcports, list) { | ||
| 3799 | if (fcport && fcport->drport && | 3826 | if (fcport && fcport->drport && |
| 3800 | atomic_read(&fcport->state) != FCS_UNCONFIGURED) | 3827 | atomic_read(&fcport->state) != FCS_UNCONFIGURED) { |
| 3828 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 3829 | |||
| 3801 | qla2x00_rport_del(fcport); | 3830 | qla2x00_rport_del(fcport); |
| 3831 | |||
| 3832 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 3833 | } | ||
| 3834 | } | ||
| 3835 | atomic_dec(&vha->vref_count); | ||
| 3836 | } | ||
| 3837 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 3802 | } | 3838 | } |
| 3803 | 3839 | ||
| 3804 | void | 3840 | void |
| @@ -3806,7 +3842,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) | |||
| 3806 | { | 3842 | { |
| 3807 | struct qla_hw_data *ha = vha->hw; | 3843 | struct qla_hw_data *ha = vha->hw; |
| 3808 | struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); | 3844 | struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); |
| 3809 | struct scsi_qla_host *tvp; | 3845 | unsigned long flags; |
| 3810 | 3846 | ||
| 3811 | vha->flags.online = 0; | 3847 | vha->flags.online = 0; |
| 3812 | ha->flags.chip_reset_done = 0; | 3848 | ha->flags.chip_reset_done = 0; |
| @@ -3824,8 +3860,18 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) | |||
| 3824 | if (atomic_read(&vha->loop_state) != LOOP_DOWN) { | 3860 | if (atomic_read(&vha->loop_state) != LOOP_DOWN) { |
| 3825 | atomic_set(&vha->loop_state, LOOP_DOWN); | 3861 | atomic_set(&vha->loop_state, LOOP_DOWN); |
| 3826 | qla2x00_mark_all_devices_lost(vha, 0); | 3862 | qla2x00_mark_all_devices_lost(vha, 0); |
| 3827 | list_for_each_entry_safe(vp, tvp, &base_vha->hw->vp_list, list) | 3863 | |
| 3864 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 3865 | list_for_each_entry(vp, &base_vha->hw->vp_list, list) { | ||
| 3866 | atomic_inc(&vp->vref_count); | ||
| 3867 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 3868 | |||
| 3828 | qla2x00_mark_all_devices_lost(vp, 0); | 3869 | qla2x00_mark_all_devices_lost(vp, 0); |
| 3870 | |||
| 3871 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 3872 | atomic_dec(&vp->vref_count); | ||
| 3873 | } | ||
| 3874 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 3829 | } else { | 3875 | } else { |
| 3830 | if (!atomic_read(&vha->loop_down_timer)) | 3876 | if (!atomic_read(&vha->loop_down_timer)) |
| 3831 | atomic_set(&vha->loop_down_timer, | 3877 | atomic_set(&vha->loop_down_timer, |
| @@ -3862,8 +3908,8 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) | |||
| 3862 | uint8_t status = 0; | 3908 | uint8_t status = 0; |
| 3863 | struct qla_hw_data *ha = vha->hw; | 3909 | struct qla_hw_data *ha = vha->hw; |
| 3864 | struct scsi_qla_host *vp; | 3910 | struct scsi_qla_host *vp; |
| 3865 | struct scsi_qla_host *tvp; | ||
| 3866 | struct req_que *req = ha->req_q_map[0]; | 3911 | struct req_que *req = ha->req_q_map[0]; |
| 3912 | unsigned long flags; | ||
| 3867 | 3913 | ||
| 3868 | if (vha->flags.online) { | 3914 | if (vha->flags.online) { |
| 3869 | qla2x00_abort_isp_cleanup(vha); | 3915 | qla2x00_abort_isp_cleanup(vha); |
| @@ -3970,10 +4016,21 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) | |||
| 3970 | DEBUG(printk(KERN_INFO | 4016 | DEBUG(printk(KERN_INFO |
| 3971 | "qla2x00_abort_isp(%ld): succeeded.\n", | 4017 | "qla2x00_abort_isp(%ld): succeeded.\n", |
| 3972 | vha->host_no)); | 4018 | vha->host_no)); |
| 3973 | list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { | 4019 | |
| 3974 | if (vp->vp_idx) | 4020 | spin_lock_irqsave(&ha->vport_slock, flags); |
| 4021 | list_for_each_entry(vp, &ha->vp_list, list) { | ||
| 4022 | if (vp->vp_idx) { | ||
| 4023 | atomic_inc(&vp->vref_count); | ||
| 4024 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 4025 | |||
| 3975 | qla2x00_vp_abort_isp(vp); | 4026 | qla2x00_vp_abort_isp(vp); |
| 4027 | |||
| 4028 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 4029 | atomic_dec(&vp->vref_count); | ||
| 4030 | } | ||
| 3976 | } | 4031 | } |
| 4032 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 4033 | |||
| 3977 | } else { | 4034 | } else { |
| 3978 | qla_printk(KERN_INFO, ha, | 4035 | qla_printk(KERN_INFO, ha, |
| 3979 | "qla2x00_abort_isp: **** FAILED ****\n"); | 4036 | "qla2x00_abort_isp: **** FAILED ****\n"); |
| @@ -5185,7 +5242,7 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) | |||
| 5185 | struct req_que *req = ha->req_q_map[0]; | 5242 | struct req_que *req = ha->req_q_map[0]; |
| 5186 | struct rsp_que *rsp = ha->rsp_q_map[0]; | 5243 | struct rsp_que *rsp = ha->rsp_q_map[0]; |
| 5187 | struct scsi_qla_host *vp; | 5244 | struct scsi_qla_host *vp; |
| 5188 | struct scsi_qla_host *tvp; | 5245 | unsigned long flags; |
| 5189 | 5246 | ||
| 5190 | status = qla2x00_init_rings(vha); | 5247 | status = qla2x00_init_rings(vha); |
| 5191 | if (!status) { | 5248 | if (!status) { |
| @@ -5272,10 +5329,21 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) | |||
| 5272 | DEBUG(printk(KERN_INFO | 5329 | DEBUG(printk(KERN_INFO |
| 5273 | "qla82xx_restart_isp(%ld): succeeded.\n", | 5330 | "qla82xx_restart_isp(%ld): succeeded.\n", |
| 5274 | vha->host_no)); | 5331 | vha->host_no)); |
| 5275 | list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { | 5332 | |
| 5276 | if (vp->vp_idx) | 5333 | spin_lock_irqsave(&ha->vport_slock, flags); |
| 5334 | list_for_each_entry(vp, &ha->vp_list, list) { | ||
| 5335 | if (vp->vp_idx) { | ||
| 5336 | atomic_inc(&vp->vref_count); | ||
| 5337 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 5338 | |||
| 5277 | qla2x00_vp_abort_isp(vp); | 5339 | qla2x00_vp_abort_isp(vp); |
| 5340 | |||
| 5341 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 5342 | atomic_dec(&vp->vref_count); | ||
| 5343 | } | ||
| 5278 | } | 5344 | } |
| 5345 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 5346 | |||
| 5279 | } else { | 5347 | } else { |
| 5280 | qla_printk(KERN_INFO, ha, | 5348 | qla_printk(KERN_INFO, ha, |
| 5281 | "qla82xx_restart_isp: **** FAILED ****\n"); | 5349 | "qla82xx_restart_isp: **** FAILED ****\n"); |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 6009b0c69488..a595ec8264f8 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
| @@ -2913,7 +2913,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, | |||
| 2913 | uint16_t stat = le16_to_cpu(rptid_entry->vp_idx); | 2913 | uint16_t stat = le16_to_cpu(rptid_entry->vp_idx); |
| 2914 | struct qla_hw_data *ha = vha->hw; | 2914 | struct qla_hw_data *ha = vha->hw; |
| 2915 | scsi_qla_host_t *vp; | 2915 | scsi_qla_host_t *vp; |
| 2916 | scsi_qla_host_t *tvp; | 2916 | unsigned long flags; |
| 2917 | 2917 | ||
| 2918 | if (rptid_entry->entry_status != 0) | 2918 | if (rptid_entry->entry_status != 0) |
| 2919 | return; | 2919 | return; |
| @@ -2945,9 +2945,12 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, | |||
| 2945 | return; | 2945 | return; |
| 2946 | } | 2946 | } |
| 2947 | 2947 | ||
| 2948 | list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) | 2948 | spin_lock_irqsave(&ha->vport_slock, flags); |
| 2949 | list_for_each_entry(vp, &ha->vp_list, list) | ||
| 2949 | if (vp_idx == vp->vp_idx) | 2950 | if (vp_idx == vp->vp_idx) |
| 2950 | break; | 2951 | break; |
| 2952 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 2953 | |||
| 2951 | if (!vp) | 2954 | if (!vp) |
| 2952 | return; | 2955 | return; |
| 2953 | 2956 | ||
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 987c5b0ca78e..bc1a7453c5d8 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c | |||
| @@ -30,6 +30,7 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) | |||
| 30 | { | 30 | { |
| 31 | uint32_t vp_id; | 31 | uint32_t vp_id; |
| 32 | struct qla_hw_data *ha = vha->hw; | 32 | struct qla_hw_data *ha = vha->hw; |
| 33 | unsigned long flags; | ||
| 33 | 34 | ||
| 34 | /* Find an empty slot and assign an vp_id */ | 35 | /* Find an empty slot and assign an vp_id */ |
| 35 | mutex_lock(&ha->vport_lock); | 36 | mutex_lock(&ha->vport_lock); |
| @@ -44,7 +45,11 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) | |||
| 44 | set_bit(vp_id, ha->vp_idx_map); | 45 | set_bit(vp_id, ha->vp_idx_map); |
| 45 | ha->num_vhosts++; | 46 | ha->num_vhosts++; |
| 46 | vha->vp_idx = vp_id; | 47 | vha->vp_idx = vp_id; |
| 48 | |||
| 49 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 47 | list_add_tail(&vha->list, &ha->vp_list); | 50 | list_add_tail(&vha->list, &ha->vp_list); |
| 51 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 52 | |||
| 48 | mutex_unlock(&ha->vport_lock); | 53 | mutex_unlock(&ha->vport_lock); |
| 49 | return vp_id; | 54 | return vp_id; |
| 50 | } | 55 | } |
| @@ -54,12 +59,31 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) | |||
| 54 | { | 59 | { |
| 55 | uint16_t vp_id; | 60 | uint16_t vp_id; |
| 56 | struct qla_hw_data *ha = vha->hw; | 61 | struct qla_hw_data *ha = vha->hw; |
| 62 | unsigned long flags = 0; | ||
| 57 | 63 | ||
| 58 | mutex_lock(&ha->vport_lock); | 64 | mutex_lock(&ha->vport_lock); |
| 65 | /* | ||
| 66 | * Wait for all pending activities to finish before removing vport from | ||
| 67 | * the list. | ||
| 68 | * Lock needs to be held for safe removal from the list (it | ||
| 69 | * ensures no active vp_list traversal while the vport is removed | ||
| 70 | * from the queue) | ||
| 71 | */ | ||
| 72 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 73 | while (atomic_read(&vha->vref_count)) { | ||
| 74 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 75 | |||
| 76 | msleep(500); | ||
| 77 | |||
| 78 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 79 | } | ||
| 80 | list_del(&vha->list); | ||
| 81 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 82 | |||
| 59 | vp_id = vha->vp_idx; | 83 | vp_id = vha->vp_idx; |
| 60 | ha->num_vhosts--; | 84 | ha->num_vhosts--; |
| 61 | clear_bit(vp_id, ha->vp_idx_map); | 85 | clear_bit(vp_id, ha->vp_idx_map); |
| 62 | list_del(&vha->list); | 86 | |
| 63 | mutex_unlock(&ha->vport_lock); | 87 | mutex_unlock(&ha->vport_lock); |
| 64 | } | 88 | } |
| 65 | 89 | ||
| @@ -68,12 +92,17 @@ qla24xx_find_vhost_by_name(struct qla_hw_data *ha, uint8_t *port_name) | |||
| 68 | { | 92 | { |
| 69 | scsi_qla_host_t *vha; | 93 | scsi_qla_host_t *vha; |
| 70 | struct scsi_qla_host *tvha; | 94 | struct scsi_qla_host *tvha; |
| 95 | unsigned long flags; | ||
| 71 | 96 | ||
| 97 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 72 | /* Locate matching device in database. */ | 98 | /* Locate matching device in database. */ |
| 73 | list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) { | 99 | list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) { |
| 74 | if (!memcmp(port_name, vha->port_name, WWN_SIZE)) | 100 | if (!memcmp(port_name, vha->port_name, WWN_SIZE)) { |
| 101 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 75 | return vha; | 102 | return vha; |
| 103 | } | ||
| 76 | } | 104 | } |
| 105 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 77 | return NULL; | 106 | return NULL; |
| 78 | } | 107 | } |
| 79 | 108 | ||
| @@ -93,6 +122,12 @@ qla24xx_find_vhost_by_name(struct qla_hw_data *ha, uint8_t *port_name) | |||
| 93 | static void | 122 | static void |
| 94 | qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) | 123 | qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) |
| 95 | { | 124 | { |
| 125 | /* | ||
| 126 | * !!! NOTE !!! | ||
| 127 | * This function, if called in contexts other than vp create, disable | ||
| 128 | * or delete, please make sure this is synchronized with the | ||
| 129 | * delete thread. | ||
| 130 | */ | ||
| 96 | fc_port_t *fcport; | 131 | fc_port_t *fcport; |
| 97 | 132 | ||
| 98 | list_for_each_entry(fcport, &vha->vp_fcports, list) { | 133 | list_for_each_entry(fcport, &vha->vp_fcports, list) { |
| @@ -194,12 +229,17 @@ qla24xx_configure_vp(scsi_qla_host_t *vha) | |||
| 194 | void | 229 | void |
| 195 | qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) | 230 | qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) |
| 196 | { | 231 | { |
| 197 | scsi_qla_host_t *vha, *tvha; | 232 | scsi_qla_host_t *vha; |
| 198 | struct qla_hw_data *ha = rsp->hw; | 233 | struct qla_hw_data *ha = rsp->hw; |
| 199 | int i = 0; | 234 | int i = 0; |
| 235 | unsigned long flags; | ||
| 200 | 236 | ||
| 201 | list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) { | 237 | spin_lock_irqsave(&ha->vport_slock, flags); |
| 238 | list_for_each_entry(vha, &ha->vp_list, list) { | ||
| 202 | if (vha->vp_idx) { | 239 | if (vha->vp_idx) { |
| 240 | atomic_inc(&vha->vref_count); | ||
| 241 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 242 | |||
| 203 | switch (mb[0]) { | 243 | switch (mb[0]) { |
| 204 | case MBA_LIP_OCCURRED: | 244 | case MBA_LIP_OCCURRED: |
| 205 | case MBA_LOOP_UP: | 245 | case MBA_LOOP_UP: |
| @@ -215,9 +255,13 @@ qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) | |||
| 215 | qla2x00_async_event(vha, rsp, mb); | 255 | qla2x00_async_event(vha, rsp, mb); |
| 216 | break; | 256 | break; |
| 217 | } | 257 | } |
| 258 | |||
| 259 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 260 | atomic_dec(&vha->vref_count); | ||
| 218 | } | 261 | } |
| 219 | i++; | 262 | i++; |
| 220 | } | 263 | } |
| 264 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 221 | } | 265 | } |
| 222 | 266 | ||
| 223 | int | 267 | int |
| @@ -297,7 +341,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) | |||
| 297 | int ret; | 341 | int ret; |
| 298 | struct qla_hw_data *ha = vha->hw; | 342 | struct qla_hw_data *ha = vha->hw; |
| 299 | scsi_qla_host_t *vp; | 343 | scsi_qla_host_t *vp; |
| 300 | struct scsi_qla_host *tvp; | 344 | unsigned long flags = 0; |
| 301 | 345 | ||
| 302 | if (vha->vp_idx) | 346 | if (vha->vp_idx) |
| 303 | return; | 347 | return; |
| @@ -309,10 +353,19 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) | |||
| 309 | if (!(ha->current_topology & ISP_CFG_F)) | 353 | if (!(ha->current_topology & ISP_CFG_F)) |
| 310 | return; | 354 | return; |
| 311 | 355 | ||
| 312 | list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { | 356 | spin_lock_irqsave(&ha->vport_slock, flags); |
| 313 | if (vp->vp_idx) | 357 | list_for_each_entry(vp, &ha->vp_list, list) { |
| 358 | if (vp->vp_idx) { | ||
| 359 | atomic_inc(&vp->vref_count); | ||
| 360 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 361 | |||
| 314 | ret = qla2x00_do_dpc_vp(vp); | 362 | ret = qla2x00_do_dpc_vp(vp); |
| 363 | |||
| 364 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 365 | atomic_dec(&vp->vref_count); | ||
| 366 | } | ||
| 315 | } | 367 | } |
| 368 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 316 | } | 369 | } |
| 317 | 370 | ||
| 318 | int | 371 | int |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8c80b49ac1c4..1e4bff695254 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
| @@ -2341,16 +2341,28 @@ probe_out: | |||
| 2341 | static void | 2341 | static void |
| 2342 | qla2x00_remove_one(struct pci_dev *pdev) | 2342 | qla2x00_remove_one(struct pci_dev *pdev) |
| 2343 | { | 2343 | { |
| 2344 | scsi_qla_host_t *base_vha, *vha, *temp; | 2344 | scsi_qla_host_t *base_vha, *vha; |
| 2345 | struct qla_hw_data *ha; | 2345 | struct qla_hw_data *ha; |
| 2346 | unsigned long flags; | ||
| 2346 | 2347 | ||
| 2347 | base_vha = pci_get_drvdata(pdev); | 2348 | base_vha = pci_get_drvdata(pdev); |
| 2348 | ha = base_vha->hw; | 2349 | ha = base_vha->hw; |
| 2349 | 2350 | ||
| 2350 | list_for_each_entry_safe(vha, temp, &ha->vp_list, list) { | 2351 | spin_lock_irqsave(&ha->vport_slock, flags); |
| 2351 | if (vha && vha->fc_vport) | 2352 | list_for_each_entry(vha, &ha->vp_list, list) { |
| 2353 | atomic_inc(&vha->vref_count); | ||
| 2354 | |||
| 2355 | if (vha && vha->fc_vport) { | ||
| 2356 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 2357 | |||
| 2352 | fc_vport_terminate(vha->fc_vport); | 2358 | fc_vport_terminate(vha->fc_vport); |
| 2359 | |||
| 2360 | spin_lock_irqsave(&ha->vport_slock, flags); | ||
| 2361 | } | ||
| 2362 | |||
| 2363 | atomic_dec(&vha->vref_count); | ||
| 2353 | } | 2364 | } |
| 2365 | spin_unlock_irqrestore(&ha->vport_slock, flags); | ||
| 2354 | 2366 | ||
| 2355 | set_bit(UNLOADING, &base_vha->dpc_flags); | 2367 | set_bit(UNLOADING, &base_vha->dpc_flags); |
| 2356 | 2368 | ||
| @@ -2975,10 +2987,17 @@ static struct qla_work_evt * | |||
| 2975 | qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) | 2987 | qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) |
| 2976 | { | 2988 | { |
| 2977 | struct qla_work_evt *e; | 2989 | struct qla_work_evt *e; |
| 2990 | uint8_t bail; | ||
| 2991 | |||
| 2992 | QLA_VHA_MARK_BUSY(vha, bail); | ||
| 2993 | if (bail) | ||
| 2994 | return NULL; | ||
| 2978 | 2995 | ||
| 2979 | e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); | 2996 | e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); |
| 2980 | if (!e) | 2997 | if (!e) { |
| 2998 | QLA_VHA_MARK_NOT_BUSY(vha); | ||
| 2981 | return NULL; | 2999 | return NULL; |
| 3000 | } | ||
| 2982 | 3001 | ||
| 2983 | INIT_LIST_HEAD(&e->list); | 3002 | INIT_LIST_HEAD(&e->list); |
| 2984 | e->type = type; | 3003 | e->type = type; |
| @@ -3135,6 +3154,9 @@ qla2x00_do_work(struct scsi_qla_host *vha) | |||
| 3135 | } | 3154 | } |
| 3136 | if (e->flags & QLA_EVT_FLAG_FREE) | 3155 | if (e->flags & QLA_EVT_FLAG_FREE) |
| 3137 | kfree(e); | 3156 | kfree(e); |
| 3157 | |||
| 3158 | /* For each work completed decrement vha ref count */ | ||
| 3159 | QLA_VHA_MARK_NOT_BUSY(vha); | ||
| 3138 | } | 3160 | } |
| 3139 | } | 3161 | } |
| 3140 | 3162 | ||
