Commit c54d557c authored by Jing Huang's avatar Jing Huang Committed by James Bottomley

[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: default avatarJing Huang <huangj@brocade.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 8a4adf1c
...@@ -473,8 +473,11 @@ bfad_im_vport_delete(struct fc_vport *fc_vport) ...@@ -473,8 +473,11 @@ bfad_im_vport_delete(struct fc_vport *fc_vport)
rc = bfa_fcs_vport_delete(&vport->fcs_vport); rc = bfa_fcs_vport_delete(&vport->fcs_vport);
spin_unlock_irqrestore(&bfad->bfad_lock, flags); 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; return -1;
}
wait_for_completion(vport->comp_del); wait_for_completion(vport->comp_del);
......
...@@ -185,6 +185,7 @@ struct bfad_s { ...@@ -185,6 +185,7 @@ struct bfad_s {
bfa_boolean_t ipfc_enabled; bfa_boolean_t ipfc_enabled;
struct fc_host_statistics link_stats; struct fc_host_statistics link_stats;
struct list_head pbc_pcfg_list; struct list_head pbc_pcfg_list;
atomic_t wq_reqcnt;
}; };
struct bfad_pcfg_s { struct bfad_pcfg_s {
......
...@@ -554,7 +554,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, ...@@ -554,7 +554,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
im_port->shost->transportt = im_port->shost->transportt =
bfad_im_scsi_vport_transport_template; 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) { if (error) {
printk(KERN_WARNING "scsi_add_host failure %d\n", error); printk(KERN_WARNING "scsi_add_host failure %d\n", error);
goto out_fc_rel; goto out_fc_rel;
...@@ -598,10 +598,12 @@ bfad_im_port_delete_handler(struct work_struct *work) ...@@ -598,10 +598,12 @@ bfad_im_port_delete_handler(struct work_struct *work)
{ {
struct bfad_im_port_s *im_port = struct bfad_im_port_s *im_port =
container_of(work, struct bfad_im_port_s, port_delete_work); 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) { if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
im_port->flags |= BFAD_PORT_DELETE; im_port->flags |= BFAD_PORT_DELETE;
fc_vport_terminate(im_port->fc_vport); 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) ...@@ -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; 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); &im_port->port_delete_work);
}
} }
void void
...@@ -696,6 +701,12 @@ void ...@@ -696,6 +701,12 @@ void
bfad_im_probe_undo(struct bfad_s *bfad) bfad_im_probe_undo(struct bfad_s *bfad)
{ {
if (bfad->im) { 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); bfad_os_destroy_workq(bfad->im);
kfree(bfad->im); kfree(bfad->im);
bfad->im = NULL; bfad->im = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment