aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa
diff options
context:
space:
mode:
authorJing Huang <huangj@brocade.com>2010-07-08 20:01:49 -0700
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 12:04:28 -0500
commitc54d557c3f6a7bbf833a8f9cffad88f34513a7c4 (patch)
tree47e06fc3992844dda1f1a29a38ce41764680141f /drivers/scsi/bfa
parent8a4adf1c906ee07a01cb47297130a71489f2e4f0 (diff)
downloadkernel_samsung_crespo-c54d557c3f6a7bbf833a8f9cffad88f34513a7c4.zip
kernel_samsung_crespo-c54d557c3f6a7bbf833a8f9cffad88f34513a7c4.tar.gz
kernel_samsung_crespo-c54d557c3f6a7bbf833a8f9cffad88f34513a7c4.tar.bz2
[SCSI] bfa: vport fixes
This patch fixes 3 bugs in vport create/delete. 1) Replace scsi_add_host() with scsi_add_host_with_dma() 2) Fix rmmod hang when there are vports configured. This is due to a race condition between the workqueue destroy in pci remove context and the vport delete works being handled. The fix is to use a counter to track the vport delete work, so that workqueue destroy will not be called until all configured vports are deleted from workqueue. 3) Fix rmmmod crash when there are PBC vport configured. PBC is not allowed to be deleted dynamically. However, if someone try to delete it, it leaves the vport is wrong state. The fix is to restore the vport back to original state when the attempt to delete pbc vport delete is failed. Signed-off-by: Jing Huang <huangj@brocade.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/bfa')
-rw-r--r--drivers/scsi/bfa/bfad_attr.c5
-rw-r--r--drivers/scsi/bfa/bfad_drv.h1
-rw-r--r--drivers/scsi/bfa/bfad_im.c15
3 files changed, 18 insertions, 3 deletions
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index 871a303..0818eb0 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -473,8 +473,11 @@ bfad_im_vport_delete(struct fc_vport *fc_vport)
rc = bfa_fcs_vport_delete(&vport->fcs_vport);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
- if (rc == BFA_STATUS_PBC)
+ if (rc == BFA_STATUS_PBC) {
+ vport->drv_port.flags &= ~BFAD_PORT_DELETE;
+ vport->comp_del = NULL;
return -1;
+ }
wait_for_completion(vport->comp_del);
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 8629f64..dcf2883 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -185,6 +185,7 @@ struct bfad_s {
bfa_boolean_t ipfc_enabled;
struct fc_host_statistics link_stats;
struct list_head pbc_pcfg_list;
+ atomic_t wq_reqcnt;
};
struct bfad_pcfg_s {
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index ffbec9b..678120b 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -554,7 +554,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
im_port->shost->transportt =
bfad_im_scsi_vport_transport_template;
- error = scsi_add_host(im_port->shost, dev);
+ error = scsi_add_host_with_dma(im_port->shost, dev, &bfad->pcidev->dev);
if (error) {
printk(KERN_WARNING "scsi_add_host failure %d\n", error);
goto out_fc_rel;
@@ -598,10 +598,12 @@ bfad_im_port_delete_handler(struct work_struct *work)
{
struct bfad_im_port_s *im_port =
container_of(work, struct bfad_im_port_s, port_delete_work);
+ struct bfad_s *bfad = im_port->bfad;
if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
im_port->flags |= BFAD_PORT_DELETE;
fc_vport_terminate(im_port->fc_vport);
+ atomic_dec(&bfad->wq_reqcnt);
}
}
@@ -634,8 +636,11 @@ bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port)
{
struct bfad_im_port_s *im_port = port->im_port;
- queue_work(bfad->im->drv_workq,
+ if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
+ atomic_inc(&bfad->wq_reqcnt);
+ queue_work(bfad->im->drv_workq,
&im_port->port_delete_work);
+ }
}
void
@@ -696,6 +701,12 @@ void
bfad_im_probe_undo(struct bfad_s *bfad)
{
if (bfad->im) {
+ while (atomic_read(&bfad->wq_reqcnt)) {
+ printk(KERN_INFO "bfa %s: waiting workq processing,"
+ " wq_reqcnt:%x\n", bfad->pci_name,
+ atomic_read(&bfad->wq_reqcnt));
+ schedule_timeout_uninterruptible(HZ);
+ }
bfad_os_destroy_workq(bfad->im);
kfree(bfad->im);
bfad->im = NULL;