aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa
diff options
context:
space:
mode:
authorJing Huang <huangj@brocade.com>2010-07-08 23:01:49 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:04:28 -0400
commitc54d557c3f6a7bbf833a8f9cffad88f34513a7c4 (patch)
tree47e06fc3992844dda1f1a29a38ce41764680141f /drivers/scsi/bfa
parent8a4adf1c906ee07a01cb47297130a71489f2e4f0 (diff)
[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 871a30363560..0818eb07ef88 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)
473 rc = bfa_fcs_vport_delete(&vport->fcs_vport); 473 rc = bfa_fcs_vport_delete(&vport->fcs_vport);
474 spin_unlock_irqrestore(&bfad->bfad_lock, flags); 474 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
475 475
476 if (rc == BFA_STATUS_PBC) 476 if (rc == BFA_STATUS_PBC) {
477 vport->drv_port.flags &= ~BFAD_PORT_DELETE;
478 vport->comp_del = NULL;
477 return -1; 479 return -1;
480 }
478 481
479 wait_for_completion(vport->comp_del); 482 wait_for_completion(vport->comp_del);
480 483
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 8629f64a5287..dcf28830feef 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -185,6 +185,7 @@ struct bfad_s {
185 bfa_boolean_t ipfc_enabled; 185 bfa_boolean_t ipfc_enabled;
186 struct fc_host_statistics link_stats; 186 struct fc_host_statistics link_stats;
187 struct list_head pbc_pcfg_list; 187 struct list_head pbc_pcfg_list;
188 atomic_t wq_reqcnt;
188}; 189};
189 190
190struct bfad_pcfg_s { 191struct bfad_pcfg_s {
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index ffbec9ba21b7..678120b70460 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,
554 im_port->shost->transportt = 554 im_port->shost->transportt =
555 bfad_im_scsi_vport_transport_template; 555 bfad_im_scsi_vport_transport_template;
556 556
557 error = scsi_add_host(im_port->shost, dev); 557 error = scsi_add_host_with_dma(im_port->shost, dev, &bfad->pcidev->dev);
558 if (error) { 558 if (error) {
559 printk(KERN_WARNING "scsi_add_host failure %d\n", error); 559 printk(KERN_WARNING "scsi_add_host failure %d\n", error);
560 goto out_fc_rel; 560 goto out_fc_rel;
@@ -598,10 +598,12 @@ bfad_im_port_delete_handler(struct work_struct *work)
598{ 598{
599 struct bfad_im_port_s *im_port = 599 struct bfad_im_port_s *im_port =
600 container_of(work, struct bfad_im_port_s, port_delete_work); 600 container_of(work, struct bfad_im_port_s, port_delete_work);
601 struct bfad_s *bfad = im_port->bfad;
601 602
602 if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) { 603 if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
603 im_port->flags |= BFAD_PORT_DELETE; 604 im_port->flags |= BFAD_PORT_DELETE;
604 fc_vport_terminate(im_port->fc_vport); 605 fc_vport_terminate(im_port->fc_vport);
606 atomic_dec(&bfad->wq_reqcnt);
605 } 607 }
606 608
607} 609}
@@ -634,8 +636,11 @@ bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port)
634{ 636{
635 struct bfad_im_port_s *im_port = port->im_port; 637 struct bfad_im_port_s *im_port = port->im_port;
636 638
637 queue_work(bfad->im->drv_workq, 639 if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
640 atomic_inc(&bfad->wq_reqcnt);
641 queue_work(bfad->im->drv_workq,
638 &im_port->port_delete_work); 642 &im_port->port_delete_work);
643 }
639} 644}
640 645
641void 646void
@@ -696,6 +701,12 @@ void
696bfad_im_probe_undo(struct bfad_s *bfad) 701bfad_im_probe_undo(struct bfad_s *bfad)
697{ 702{
698 if (bfad->im) { 703 if (bfad->im) {
704 while (atomic_read(&bfad->wq_reqcnt)) {
705 printk(KERN_INFO "bfa %s: waiting workq processing,"
706 " wq_reqcnt:%x\n", bfad->pci_name,
707 atomic_read(&bfad->wq_reqcnt));
708 schedule_timeout_uninterruptible(HZ);
709 }
699 bfad_os_destroy_workq(bfad->im); 710 bfad_os_destroy_workq(bfad->im);
700 kfree(bfad->im); 711 kfree(bfad->im);
701 bfad->im = NULL; 712 bfad->im = NULL;