diff options
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvfc.c')
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 122 |
1 files changed, 83 insertions, 39 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) | |||
3715 | static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) | 3715 | static 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 | **/ | ||
4093 | static 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; |