diff options
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 98 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.h | 11 |
2 files changed, 106 insertions, 3 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 0ac2dedb413c..ea4abee7a2a9 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c | |||
@@ -3123,6 +3123,7 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) | |||
3123 | 3123 | ||
3124 | vhost->discovery_threads--; | 3124 | vhost->discovery_threads--; |
3125 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | 3125 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); |
3126 | del_timer(&tgt->timer); | ||
3126 | 3127 | ||
3127 | switch (status) { | 3128 | switch (status) { |
3128 | case IBMVFC_MAD_SUCCESS: | 3129 | case IBMVFC_MAD_SUCCESS: |
@@ -3179,9 +3180,89 @@ static void ibmvfc_init_passthru(struct ibmvfc_event *evt) | |||
3179 | } | 3180 | } |
3180 | 3181 | ||
3181 | /** | 3182 | /** |
3183 | * ibmvfc_tgt_adisc_cancel_done - Completion handler when cancelling an ADISC | ||
3184 | * @evt: ibmvfc event struct | ||
3185 | * | ||
3186 | * Just cleanup this event struct. Everything else is handled by | ||
3187 | * the ADISC completion handler. If the ADISC never actually comes | ||
3188 | * back, we still have the timer running on the ADISC event struct | ||
3189 | * which will fire and cause the CRQ to get reset. | ||
3190 | * | ||
3191 | **/ | ||
3192 | static void ibmvfc_tgt_adisc_cancel_done(struct ibmvfc_event *evt) | ||
3193 | { | ||
3194 | struct ibmvfc_host *vhost = evt->vhost; | ||
3195 | struct ibmvfc_target *tgt = evt->tgt; | ||
3196 | |||
3197 | tgt_dbg(tgt, "ADISC cancel complete\n"); | ||
3198 | vhost->abort_threads--; | ||
3199 | ibmvfc_free_event(evt); | ||
3200 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
3201 | wake_up(&vhost->work_wait_q); | ||
3202 | } | ||
3203 | |||
3204 | /** | ||
3205 | * ibmvfc_adisc_timeout - Handle an ADISC timeout | ||
3206 | * @tgt: ibmvfc target struct | ||
3207 | * | ||
3208 | * If an ADISC times out, send a cancel. If the cancel times | ||
3209 | * out, reset the CRQ. When the ADISC comes back as cancelled, | ||
3210 | * log back into the target. | ||
3211 | **/ | ||
3212 | static void ibmvfc_adisc_timeout(struct ibmvfc_target *tgt) | ||
3213 | { | ||
3214 | struct ibmvfc_host *vhost = tgt->vhost; | ||
3215 | struct ibmvfc_event *evt; | ||
3216 | struct ibmvfc_tmf *tmf; | ||
3217 | unsigned long flags; | ||
3218 | int rc; | ||
3219 | |||
3220 | tgt_dbg(tgt, "ADISC timeout\n"); | ||
3221 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3222 | if (vhost->abort_threads >= disc_threads || | ||
3223 | tgt->action != IBMVFC_TGT_ACTION_INIT_WAIT || | ||
3224 | vhost->state != IBMVFC_INITIALIZING || | ||
3225 | vhost->action != IBMVFC_HOST_ACTION_QUERY_TGTS) { | ||
3226 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3227 | return; | ||
3228 | } | ||
3229 | |||
3230 | vhost->abort_threads++; | ||
3231 | kref_get(&tgt->kref); | ||
3232 | evt = ibmvfc_get_event(vhost); | ||
3233 | ibmvfc_init_event(evt, ibmvfc_tgt_adisc_cancel_done, IBMVFC_MAD_FORMAT); | ||
3234 | |||
3235 | evt->tgt = tgt; | ||
3236 | tmf = &evt->iu.tmf; | ||
3237 | memset(tmf, 0, sizeof(*tmf)); | ||
3238 | tmf->common.version = 1; | ||
3239 | tmf->common.opcode = IBMVFC_TMF_MAD; | ||
3240 | tmf->common.length = sizeof(*tmf); | ||
3241 | tmf->scsi_id = tgt->scsi_id; | ||
3242 | tmf->cancel_key = tgt->cancel_key; | ||
3243 | |||
3244 | rc = ibmvfc_send_event(evt, vhost, default_timeout); | ||
3245 | |||
3246 | if (rc) { | ||
3247 | tgt_err(tgt, "Failed to send cancel event for ADISC. rc=%d\n", rc); | ||
3248 | vhost->abort_threads--; | ||
3249 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
3250 | __ibmvfc_reset_host(vhost); | ||
3251 | } else | ||
3252 | tgt_dbg(tgt, "Attempting to cancel ADISC\n"); | ||
3253 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3254 | } | ||
3255 | |||
3256 | /** | ||
3182 | * ibmvfc_tgt_adisc - Initiate an ADISC for specified target | 3257 | * ibmvfc_tgt_adisc - Initiate an ADISC for specified target |
3183 | * @tgt: ibmvfc target struct | 3258 | * @tgt: ibmvfc target struct |
3184 | * | 3259 | * |
3260 | * When sending an ADISC we end up with two timers running. The | ||
3261 | * first timer is the timer in the ibmvfc target struct. If this | ||
3262 | * fires, we send a cancel to the target. The second timer is the | ||
3263 | * timer on the ibmvfc event for the ADISC, which is longer. If that | ||
3264 | * fires, it means the ADISC timed out and our attempt to cancel it | ||
3265 | * also failed, so we need to reset the CRQ. | ||
3185 | **/ | 3266 | **/ |
3186 | static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) | 3267 | static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) |
3187 | { | 3268 | { |
@@ -3202,6 +3283,7 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) | |||
3202 | mad = &evt->iu.passthru; | 3283 | mad = &evt->iu.passthru; |
3203 | mad->iu.flags = IBMVFC_FC_ELS; | 3284 | mad->iu.flags = IBMVFC_FC_ELS; |
3204 | mad->iu.scsi_id = tgt->scsi_id; | 3285 | mad->iu.scsi_id = tgt->scsi_id; |
3286 | mad->iu.cancel_key = tgt->cancel_key; | ||
3205 | 3287 | ||
3206 | mad->fc_iu.payload[0] = IBMVFC_ADISC; | 3288 | mad->fc_iu.payload[0] = IBMVFC_ADISC; |
3207 | memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name, | 3289 | memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name, |
@@ -3210,9 +3292,19 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) | |||
3210 | sizeof(vhost->login_buf->resp.node_name)); | 3292 | sizeof(vhost->login_buf->resp.node_name)); |
3211 | mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff; | 3293 | mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff; |
3212 | 3294 | ||
3295 | if (timer_pending(&tgt->timer)) | ||
3296 | mod_timer(&tgt->timer, jiffies + (IBMVFC_ADISC_TIMEOUT * HZ)); | ||
3297 | else { | ||
3298 | tgt->timer.data = (unsigned long) tgt; | ||
3299 | tgt->timer.expires = jiffies + (IBMVFC_ADISC_TIMEOUT * HZ); | ||
3300 | tgt->timer.function = (void (*)(unsigned long))ibmvfc_adisc_timeout; | ||
3301 | add_timer(&tgt->timer); | ||
3302 | } | ||
3303 | |||
3213 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | 3304 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); |
3214 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | 3305 | if (ibmvfc_send_event(evt, vhost, IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT)) { |
3215 | vhost->discovery_threads--; | 3306 | vhost->discovery_threads--; |
3307 | del_timer(&tgt->timer); | ||
3216 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | 3308 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); |
3217 | kref_put(&tgt->kref, ibmvfc_release_tgt); | 3309 | kref_put(&tgt->kref, ibmvfc_release_tgt); |
3218 | } else | 3310 | } else |
@@ -3340,6 +3432,8 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) | |||
3340 | tgt->new_scsi_id = scsi_id; | 3432 | tgt->new_scsi_id = scsi_id; |
3341 | tgt->vhost = vhost; | 3433 | tgt->vhost = vhost; |
3342 | tgt->need_login = 1; | 3434 | tgt->need_login = 1; |
3435 | tgt->cancel_key = vhost->task_set++; | ||
3436 | init_timer(&tgt->timer); | ||
3343 | kref_init(&tgt->kref); | 3437 | kref_init(&tgt->kref); |
3344 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | 3438 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); |
3345 | spin_lock_irqsave(vhost->host->host_lock, flags); | 3439 | spin_lock_irqsave(vhost->host->host_lock, flags); |
@@ -3734,6 +3828,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) | |||
3734 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | 3828 | spin_unlock_irqrestore(vhost->host->host_lock, flags); |
3735 | if (rport) | 3829 | if (rport) |
3736 | fc_remote_port_delete(rport); | 3830 | fc_remote_port_delete(rport); |
3831 | del_timer_sync(&tgt->timer); | ||
3737 | kref_put(&tgt->kref, ibmvfc_release_tgt); | 3832 | kref_put(&tgt->kref, ibmvfc_release_tgt); |
3738 | return; | 3833 | return; |
3739 | } | 3834 | } |
@@ -4061,6 +4156,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
4061 | vhost->dev = dev; | 4156 | vhost->dev = dev; |
4062 | vhost->partition_number = -1; | 4157 | vhost->partition_number = -1; |
4063 | vhost->log_level = log_level; | 4158 | vhost->log_level = log_level; |
4159 | vhost->task_set = 1; | ||
4064 | strcpy(vhost->partition_name, "UNKNOWN"); | 4160 | strcpy(vhost->partition_name, "UNKNOWN"); |
4065 | init_waitqueue_head(&vhost->work_wait_q); | 4161 | init_waitqueue_head(&vhost->work_wait_q); |
4066 | init_waitqueue_head(&vhost->init_wait_q); | 4162 | init_waitqueue_head(&vhost->init_wait_q); |
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 70107522e3a9..0f14fd3c40d2 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h | |||
@@ -33,6 +33,10 @@ | |||
33 | #define IBMVFC_DRIVER_DATE "(November 14, 2008)" | 33 | #define IBMVFC_DRIVER_DATE "(November 14, 2008)" |
34 | 34 | ||
35 | #define IBMVFC_DEFAULT_TIMEOUT 60 | 35 | #define IBMVFC_DEFAULT_TIMEOUT 60 |
36 | #define IBMVFC_ADISC_CANCEL_TIMEOUT 45 | ||
37 | #define IBMVFC_ADISC_TIMEOUT 15 | ||
38 | #define IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT \ | ||
39 | (IBMVFC_ADISC_TIMEOUT + IBMVFC_ADISC_CANCEL_TIMEOUT) | ||
36 | #define IBMVFC_INIT_TIMEOUT 120 | 40 | #define IBMVFC_INIT_TIMEOUT 120 |
37 | #define IBMVFC_MAX_REQUESTS_DEFAULT 100 | 41 | #define IBMVFC_MAX_REQUESTS_DEFAULT 100 |
38 | 42 | ||
@@ -53,9 +57,9 @@ | |||
53 | * Ensure we have resources for ERP and initialization: | 57 | * Ensure we have resources for ERP and initialization: |
54 | * 1 for ERP | 58 | * 1 for ERP |
55 | * 1 for initialization | 59 | * 1 for initialization |
56 | * 1 for each discovery thread | 60 | * 2 for each discovery thread |
57 | */ | 61 | */ |
58 | #define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + disc_threads) | 62 | #define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + (disc_threads * 2)) |
59 | 63 | ||
60 | #define IBMVFC_MAD_SUCCESS 0x00 | 64 | #define IBMVFC_MAD_SUCCESS 0x00 |
61 | #define IBMVFC_MAD_NOT_SUPPORTED 0xF1 | 65 | #define IBMVFC_MAD_NOT_SUPPORTED 0xF1 |
@@ -585,10 +589,12 @@ struct ibmvfc_target { | |||
585 | enum ibmvfc_target_action action; | 589 | enum ibmvfc_target_action action; |
586 | int need_login; | 590 | int need_login; |
587 | int init_retries; | 591 | int init_retries; |
592 | u32 cancel_key; | ||
588 | struct ibmvfc_service_parms service_parms; | 593 | struct ibmvfc_service_parms service_parms; |
589 | struct ibmvfc_service_parms service_parms_change; | 594 | struct ibmvfc_service_parms service_parms_change; |
590 | struct fc_rport_identifiers ids; | 595 | struct fc_rport_identifiers ids; |
591 | void (*job_step) (struct ibmvfc_target *); | 596 | void (*job_step) (struct ibmvfc_target *); |
597 | struct timer_list timer; | ||
592 | struct kref kref; | 598 | struct kref kref; |
593 | }; | 599 | }; |
594 | 600 | ||
@@ -672,6 +678,7 @@ struct ibmvfc_host { | |||
672 | int task_set; | 678 | int task_set; |
673 | int init_retries; | 679 | int init_retries; |
674 | int discovery_threads; | 680 | int discovery_threads; |
681 | int abort_threads; | ||
675 | int client_migrated; | 682 | int client_migrated; |
676 | int reinit; | 683 | int reinit; |
677 | int delay_init; | 684 | int delay_init; |