aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c98
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h11
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 **/
3192static 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 **/
3212static 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 **/
3186static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) 3267static 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;