aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ibmvscsi
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2009-05-28 17:17:28 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-06-08 14:07:42 -0400
commit43c8da907ccc656935d1085701f4db83385d8a59 (patch)
tree586046bab83b676553104d7b80894863ba31872a /drivers/scsi/ibmvscsi
parent7d0e462247241b8ec2d377306203b58c7f423553 (diff)
[SCSI] ibmvfc: Fix deadlock in EH
Fixes the following deadlock scenario shown below. We currently allow queuecommand to send commands when the ibmvfc workqueue is scanning for new rports, so we should also allow EH to function at this time as well. scsi_eh_3 D 0000000000000000 12304 1279 2 Call Trace: [c0000002f7257730] [c0000002f72577e0] 0xc0000002f72577e0 (unreliable) [c0000002f7257900] [c0000000000118f4] .__switch_to+0x158/0x1a0 [c0000002f72579a0] [c0000000004f8b40] .schedule+0x8d4/0x9dc [c0000002f7257b60] [c0000000004f8f08] .schedule_timeout+0xa8/0xe8 [c0000002f7257c50] [d0000000001d23e0] .ibmvfc_wait_while_resetting+0xe4/0x140 [ibmvfc] [c0000002f7257d20] [d0000000001d3984] .ibmvfc_eh_abort_handler+0x60/0xe4 [ibmvfc] [c0000002f7257dc0] [d000000000366714] .scsi_error_handler+0x38c/0x674 [scsi_mod] [c0000002f7257f00] [c0000000000a7470] .kthread+0x78/0xc4 [c0000002f7257f90] [c000000000029b8c] .kernel_thread+0x4c/0x68 ibmvfc_3 D 0000000000000000 12432 1280 2 Call Trace: [c0000002f7253540] [c0000002f72535f0] 0xc0000002f72535f0 (unreliable) [c0000002f7253710] [c0000000000118f4] .__switch_to+0x158/0x1a0 [c0000002f72537b0] [c0000000004f8b40] .schedule+0x8d4/0x9dc [c0000002f7253970] [c0000000004f8e98] .schedule_timeout+0x38/0xe8 [c0000002f7253a60] [c0000000004f80cc] .wait_for_common+0x138/0x220 [c0000002f7253b40] [c0000000000a2784] .flush_cpu_workqueue+0xac/0xcc [c0000002f7253c10] [c0000000000a2960] .flush_workqueue+0x58/0xa0 [c0000002f7253ca0] [d0000000000827fc] .fc_flush_work+0x4c/0x64 [scsi_transport_fc] [c0000002f7253d20] [d000000000082db4] .fc_remote_port_add+0x48/0x6c4 [scsi_transport_fc] [c0000002f7253dd0] [d0000000001d7d04] .ibmvfc_work+0x820/0xa7c [ibmvfc] [c0000002f7253f00] [c0000000000a7470] .kthread+0x78/0xc4 [c0000002f7253f90] [c000000000029b8c] .kernel_thread+0x4c/0x68 fc_wq_3 D 0000000000000000 10720 1283 2 Call Trace: [c0000002f559ac30] [c0000002f559ace0] 0xc0000002f559ace0 (unreliable) [c0000002f559ae00] [c0000000000118f4] .__switch_to+0x158/0x1a0 [c0000002f559aea0] [c0000000004f8b40] .schedule+0x8d4/0x9dc [c0000002f559b060] [c0000000004f8e98] .schedule_timeout+0x38/0xe8 [c0000002f559b150] [c0000000004f80cc] .wait_for_common+0x138/0x220 [c0000002f559b230] [c0000000002721c4] .blk_execute_rq+0xb4/0x100 [c0000002f559b360] [d00000000036a1f8] .scsi_execute+0x118/0x194 [scsi_mod] [c0000002f559b420] [d00000000036a32c] .scsi_execute_req+0xb8/0x124 [scsi_mod] [c0000002f559b500] [d0000000000c1330] .sd_sync_cache+0x8c/0x108 [sd_mod] [c0000002f559b5e0] [d0000000000c15b4] .sd_shutdown+0x9c/0x158 [sd_mod] [c0000002f559b660] [d0000000000c16d0] .sd_remove+0x60/0xb4 [sd_mod] [c0000002f559b700] [c000000000392ecc] .__device_release_driver+0xd0/0x118 [c0000002f559b7a0] [c000000000393080] .device_release_driver+0x30/0x54 [c0000002f559b830] [c000000000392108] .bus_remove_device+0x128/0x16c [c0000002f559b8d0] [c00000000038f94c] .device_del+0x158/0x234 [c0000002f559b960] [d00000000036f078] .__scsi_remove_device+0x5c/0xd4 [scsi_mod] [c0000002f559b9f0] [d00000000036f124] .scsi_remove_device+0x34/0x58 [scsi_mod] [c0000002f559ba80] [d00000000036f204] .__scsi_remove_target+0xb4/0x120 [scsi_mod] [c0000002f559bb10] [d00000000036f338] .__remove_child+0x2c/0x44 [scsi_mod] [c0000002f559bb90] [c00000000038f11c] .device_for_each_child+0x54/0xb4 [c0000002f559bc50] [d00000000036f2e0] .scsi_remove_target+0x70/0x9c [scsi_mod] [c0000002f559bce0] [d000000000083454] .fc_starget_delete+0x24/0x3c [scsi_transport_fc] [c0000002f559bd70] [c0000000000a2368] .run_workqueue+0x118/0x208 [c0000002f559be30] [c0000000000a2580] .worker_thread+0x128/0x154 [c0000002f559bf00] [c0000000000a7470] .kthread+0x78/0xc4 [c0000002f559bf90] [c000000000029b8c] .kernel_thread+0x4c/0x68 Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/ibmvscsi')
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c122
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h5
2 files changed, 86 insertions, 41 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 182c8e75aaf0..76ae266b07c4 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -431,6 +431,8 @@ static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt,
431 case IBMVFC_TGT_ACTION_DEL_RPORT: 431 case IBMVFC_TGT_ACTION_DEL_RPORT:
432 break; 432 break;
433 default: 433 default:
434 if (action == IBMVFC_TGT_ACTION_DEL_RPORT)
435 tgt->add_rport = 0;
434 tgt->action = action; 436 tgt->action = action;
435 break; 437 break;
436 } 438 }
@@ -483,7 +485,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
483 switch (vhost->action) { 485 switch (vhost->action) {
484 case IBMVFC_HOST_ACTION_INIT_WAIT: 486 case IBMVFC_HOST_ACTION_INIT_WAIT:
485 case IBMVFC_HOST_ACTION_NONE: 487 case IBMVFC_HOST_ACTION_NONE:
486 case IBMVFC_HOST_ACTION_TGT_ADD: 488 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
487 vhost->action = action; 489 vhost->action = action;
488 break; 490 break;
489 default: 491 default:
@@ -498,7 +500,6 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
498 case IBMVFC_HOST_ACTION_TGT_DEL: 500 case IBMVFC_HOST_ACTION_TGT_DEL:
499 case IBMVFC_HOST_ACTION_QUERY_TGTS: 501 case IBMVFC_HOST_ACTION_QUERY_TGTS:
500 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: 502 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
501 case IBMVFC_HOST_ACTION_TGT_ADD:
502 case IBMVFC_HOST_ACTION_NONE: 503 case IBMVFC_HOST_ACTION_NONE:
503 default: 504 default:
504 vhost->action = action; 505 vhost->action = action;
@@ -2306,7 +2307,7 @@ static int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
2306 done = 1; 2307 done = 1;
2307 } 2308 }
2308 2309
2309 if (vhost->state != IBMVFC_NO_CRQ && vhost->action == IBMVFC_HOST_ACTION_NONE) 2310 if (vhost->scan_complete)
2310 done = 1; 2311 done = 1;
2311 spin_unlock_irqrestore(shost->host_lock, flags); 2312 spin_unlock_irqrestore(shost->host_lock, flags);
2312 return done; 2313 return done;
@@ -2820,7 +2821,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
2820 tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET; 2821 tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET;
2821 if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC) 2822 if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC)
2822 tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; 2823 tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
2823 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); 2824 tgt->add_rport = 1;
2824 } else 2825 } else
2825 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); 2826 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
2826 } else if (prli_rsp[index].retry) 2827 } else if (prli_rsp[index].retry)
@@ -3660,7 +3661,6 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
3660 return 1; 3661 return 1;
3661 case IBMVFC_HOST_ACTION_INIT: 3662 case IBMVFC_HOST_ACTION_INIT:
3662 case IBMVFC_HOST_ACTION_ALLOC_TGTS: 3663 case IBMVFC_HOST_ACTION_ALLOC_TGTS:
3663 case IBMVFC_HOST_ACTION_TGT_ADD:
3664 case IBMVFC_HOST_ACTION_TGT_DEL: 3664 case IBMVFC_HOST_ACTION_TGT_DEL:
3665 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: 3665 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
3666 case IBMVFC_HOST_ACTION_QUERY: 3666 case IBMVFC_HOST_ACTION_QUERY:
@@ -3715,25 +3715,26 @@ static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events)
3715static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) 3715static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
3716{ 3716{
3717 struct ibmvfc_host *vhost = tgt->vhost; 3717 struct ibmvfc_host *vhost = tgt->vhost;
3718 struct fc_rport *rport = tgt->rport; 3718 struct fc_rport *rport;
3719 unsigned long flags; 3719 unsigned long flags;
3720 3720
3721 if (rport) { 3721 tgt_dbg(tgt, "Adding rport\n");
3722 tgt_dbg(tgt, "Setting rport roles\n"); 3722 rport = fc_remote_port_add(vhost->host, 0, &tgt->ids);
3723 fc_remote_port_rolechg(rport, tgt->ids.roles); 3723 spin_lock_irqsave(vhost->host->host_lock, flags);
3724 spin_lock_irqsave(vhost->host->host_lock, flags); 3724
3725 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); 3725 if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
3726 tgt_dbg(tgt, "Deleting rport\n");
3727 list_del(&tgt->queue);
3726 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3728 spin_unlock_irqrestore(vhost->host->host_lock, flags);
3729 fc_remote_port_delete(rport);
3730 del_timer_sync(&tgt->timer);
3731 kref_put(&tgt->kref, ibmvfc_release_tgt);
3727 return; 3732 return;
3728 } 3733 }
3729 3734
3730 tgt_dbg(tgt, "Adding rport\n");
3731 rport = fc_remote_port_add(vhost->host, 0, &tgt->ids);
3732 spin_lock_irqsave(vhost->host->host_lock, flags);
3733 tgt->rport = rport;
3734 ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
3735 if (rport) { 3735 if (rport) {
3736 tgt_dbg(tgt, "rport add succeeded\n"); 3736 tgt_dbg(tgt, "rport add succeeded\n");
3737 tgt->rport = rport;
3737 rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; 3738 rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
3738 rport->supported_classes = 0; 3739 rport->supported_classes = 0;
3739 tgt->target_id = rport->scsi_target_id; 3740 tgt->target_id = rport->scsi_target_id;
@@ -3811,11 +3812,21 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
3811 3812
3812 if (vhost->state == IBMVFC_INITIALIZING) { 3813 if (vhost->state == IBMVFC_INITIALIZING) {
3813 if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { 3814 if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) {
3814 ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); 3815 if (vhost->reinit) {
3815 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); 3816 vhost->reinit = 0;
3816 vhost->init_retries = 0; 3817 scsi_block_requests(vhost->host);
3817 spin_unlock_irqrestore(vhost->host->host_lock, flags); 3818 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
3818 scsi_unblock_requests(vhost->host); 3819 spin_unlock_irqrestore(vhost->host->host_lock, flags);
3820 } else {
3821 ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE);
3822 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
3823 wake_up(&vhost->init_wait_q);
3824 schedule_work(&vhost->rport_add_work_q);
3825 vhost->init_retries = 0;
3826 spin_unlock_irqrestore(vhost->host->host_lock, flags);
3827 scsi_unblock_requests(vhost->host);
3828 }
3829
3819 return; 3830 return;
3820 } else { 3831 } else {
3821 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); 3832 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
@@ -3846,24 +3857,6 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
3846 if (!ibmvfc_dev_init_to_do(vhost)) 3857 if (!ibmvfc_dev_init_to_do(vhost))
3847 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED); 3858 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED);
3848 break; 3859 break;
3849 case IBMVFC_HOST_ACTION_TGT_ADD:
3850 list_for_each_entry(tgt, &vhost->targets, queue) {
3851 if (tgt->action == IBMVFC_TGT_ACTION_ADD_RPORT) {
3852 spin_unlock_irqrestore(vhost->host->host_lock, flags);
3853 ibmvfc_tgt_add_rport(tgt);
3854 return;
3855 }
3856 }
3857
3858 if (vhost->reinit && !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
3859 vhost->reinit = 0;
3860 scsi_block_requests(vhost->host);
3861 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
3862 } else {
3863 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
3864 wake_up(&vhost->init_wait_q);
3865 }
3866 break;
3867 default: 3860 default:
3868 break; 3861 break;
3869 }; 3862 };
@@ -4093,6 +4086,56 @@ nomem:
4093} 4086}
4094 4087
4095/** 4088/**
4089 * ibmvfc_rport_add_thread - Worker thread for rport adds
4090 * @work: work struct
4091 *
4092 **/
4093static void ibmvfc_rport_add_thread(struct work_struct *work)
4094{
4095 struct ibmvfc_host *vhost = container_of(work, struct ibmvfc_host,
4096 rport_add_work_q);
4097 struct ibmvfc_target *tgt;
4098 struct fc_rport *rport;
4099 unsigned long flags;
4100 int did_work;
4101
4102 ENTER;
4103 spin_lock_irqsave(vhost->host->host_lock, flags);
4104 do {
4105 did_work = 0;
4106 if (vhost->state != IBMVFC_ACTIVE)
4107 break;
4108
4109 list_for_each_entry(tgt, &vhost->targets, queue) {
4110 if (tgt->add_rport) {
4111 did_work = 1;
4112 tgt->add_rport = 0;
4113 kref_get(&tgt->kref);
4114 rport = tgt->rport;
4115 if (!rport) {
4116 spin_unlock_irqrestore(vhost->host->host_lock, flags);
4117 ibmvfc_tgt_add_rport(tgt);
4118 } else if (get_device(&rport->dev)) {
4119 spin_unlock_irqrestore(vhost->host->host_lock, flags);
4120 tgt_dbg(tgt, "Setting rport roles\n");
4121 fc_remote_port_rolechg(rport, tgt->ids.roles);
4122 put_device(&rport->dev);
4123 }
4124
4125 kref_put(&tgt->kref, ibmvfc_release_tgt);
4126 spin_lock_irqsave(vhost->host->host_lock, flags);
4127 break;
4128 }
4129 }
4130 } while(did_work);
4131
4132 if (vhost->state == IBMVFC_ACTIVE)
4133 vhost->scan_complete = 1;
4134 spin_unlock_irqrestore(vhost->host->host_lock, flags);
4135 LEAVE;
4136}
4137
4138/**
4096 * ibmvfc_probe - Adapter hot plug add entry point 4139 * ibmvfc_probe - Adapter hot plug add entry point
4097 * @vdev: vio device struct 4140 * @vdev: vio device struct
4098 * @id: vio device id struct 4141 * @id: vio device id struct
@@ -4135,6 +4178,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
4135 strcpy(vhost->partition_name, "UNKNOWN"); 4178 strcpy(vhost->partition_name, "UNKNOWN");
4136 init_waitqueue_head(&vhost->work_wait_q); 4179 init_waitqueue_head(&vhost->work_wait_q);
4137 init_waitqueue_head(&vhost->init_wait_q); 4180 init_waitqueue_head(&vhost->init_wait_q);
4181 INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread);
4138 4182
4139 if ((rc = ibmvfc_alloc_mem(vhost))) 4183 if ((rc = ibmvfc_alloc_mem(vhost)))
4140 goto free_scsi_host; 4184 goto free_scsi_host;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 4dac3560c1a4..3a6a725fd396 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -575,7 +575,6 @@ enum ibmvfc_target_action {
575 IBMVFC_TGT_ACTION_NONE = 0, 575 IBMVFC_TGT_ACTION_NONE = 0,
576 IBMVFC_TGT_ACTION_INIT, 576 IBMVFC_TGT_ACTION_INIT,
577 IBMVFC_TGT_ACTION_INIT_WAIT, 577 IBMVFC_TGT_ACTION_INIT_WAIT,
578 IBMVFC_TGT_ACTION_ADD_RPORT,
579 IBMVFC_TGT_ACTION_DEL_RPORT, 578 IBMVFC_TGT_ACTION_DEL_RPORT,
580}; 579};
581 580
@@ -588,6 +587,7 @@ struct ibmvfc_target {
588 int target_id; 587 int target_id;
589 enum ibmvfc_target_action action; 588 enum ibmvfc_target_action action;
590 int need_login; 589 int need_login;
590 int add_rport;
591 int init_retries; 591 int init_retries;
592 u32 cancel_key; 592 u32 cancel_key;
593 struct ibmvfc_service_parms service_parms; 593 struct ibmvfc_service_parms service_parms;
@@ -635,7 +635,6 @@ enum ibmvfc_host_action {
635 IBMVFC_HOST_ACTION_ALLOC_TGTS, 635 IBMVFC_HOST_ACTION_ALLOC_TGTS,
636 IBMVFC_HOST_ACTION_TGT_INIT, 636 IBMVFC_HOST_ACTION_TGT_INIT,
637 IBMVFC_HOST_ACTION_TGT_DEL_FAILED, 637 IBMVFC_HOST_ACTION_TGT_DEL_FAILED,
638 IBMVFC_HOST_ACTION_TGT_ADD,
639}; 638};
640 639
641enum ibmvfc_host_state { 640enum ibmvfc_host_state {
@@ -682,6 +681,7 @@ struct ibmvfc_host {
682 int client_migrated; 681 int client_migrated;
683 int reinit; 682 int reinit;
684 int delay_init; 683 int delay_init;
684 int scan_complete;
685 int events_to_log; 685 int events_to_log;
686#define IBMVFC_AE_LINKUP 0x0001 686#define IBMVFC_AE_LINKUP 0x0001
687#define IBMVFC_AE_LINKDOWN 0x0002 687#define IBMVFC_AE_LINKDOWN 0x0002
@@ -692,6 +692,7 @@ struct ibmvfc_host {
692 void (*job_step) (struct ibmvfc_host *); 692 void (*job_step) (struct ibmvfc_host *);
693 struct task_struct *work_thread; 693 struct task_struct *work_thread;
694 struct tasklet_struct tasklet; 694 struct tasklet_struct tasklet;
695 struct work_struct rport_add_work_q;
695 wait_queue_head_t init_wait_q; 696 wait_queue_head_t init_wait_q;
696 wait_queue_head_t work_wait_q; 697 wait_queue_head_t work_wait_q;
697}; 698};