diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_mid.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 67 |
1 files changed, 60 insertions, 7 deletions
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 |