struct fc_rport         *rport;
        struct mptfc_rport_info *ri;
        int                     new_ri = 1;
-       u64                     pn;
-       unsigned long           flags;
+       u64                     pn, nn;
        VirtTarget              *vtarget;
 
        if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
                return;
 
        /* scan list looking for a match */
-       spin_lock_irqsave(&ioc->fc_rport_lock, flags);
        list_for_each_entry(ri, &ioc->fc_rports, list) {
                pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
                if (pn == rport_ids.port_name) {        /* match */
                }
        }
        if (new_ri) {   /* allocate one */
-               spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
                ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
                if (!ri)
                        return;
-               spin_lock_irqsave(&ioc->fc_rport_lock, flags);
                list_add_tail(&ri->list, &ioc->fc_rports);
        }
 
        /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
        if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
                ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
-               spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
                rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
-               spin_lock_irqsave(&ioc->fc_rport_lock, flags);
                if (rport) {
                        ri->rport = rport;
                        if (new_ri) /* may have been reset by user */
                                rport->dev_loss_tmo = mptfc_dev_loss_tmo;
-                       *((struct mptfc_rport_info **)rport->dd_data) = ri;
                        /*
                         * if already mapped, remap here.  If not mapped,
                         * target_alloc will allocate vtarget and map,
                                        vtarget->target_id = pg0->CurrentTargetID;
                                        vtarget->bus_id = pg0->CurrentBus;
                                }
-                               ri->remap_needed = 0;
                        }
+                       /* once dd_data is filled in, commands will issue to hardware */
+                       *((struct mptfc_rport_info **)rport->dd_data) = ri;
+
+                       pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+                       nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
                        dfcprintk ((MYIOC_s_INFO_FMT
                                "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
                                "rport tid %d, tmo %d\n",
                                        ioc->name,
                                        ioc->sh->host_no,
                                        pg0->PortIdentifier,
-                                       pg0->WWNN,
-                                       pg0->WWPN,
+                                       (unsigned long long)nn,
+                                       (unsigned long long)pn,
                                        pg0->CurrentTargetID,
                                        ri->rport->scsi_target_id,
                                        ri->rport->dev_loss_tmo));
                        ri = NULL;
                }
        }
-       spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
-
 }
 
 /*
                        vtarget->target_id = ri->pg0.CurrentTargetID;
                        vtarget->bus_id = ri->pg0.CurrentBus;
                        ri->starget = starget;
-                       ri->remap_needed = 0;
                        rc = 0;
                }
        }
        VirtDevice              *vdev;
        struct scsi_target      *starget;
        struct fc_rport         *rport;
-       unsigned long           flags;
 
 
-       rport = starget_to_rport(scsi_target(sdev));
+       starget = scsi_target(sdev);
+       rport = starget_to_rport(starget);
 
        if (!rport || fc_remote_port_chkready(rport))
                return -ENXIO;
                return -ENOMEM;
        }
 
-       spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
 
        sdev->hostdata = vdev;
-       starget = scsi_target(sdev);
        vtarget = starget->hostdata;
 
        if (vtarget->num_luns == 0) {
        vdev->vtarget = vtarget;
        vdev->lun = sdev->lun;
 
-       spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
-
        vtarget->num_luns++;
 
+
 #ifdef DMPT_DEBUG_FC
-        {
+       {
+       u64 nn, pn;
        struct mptfc_rport_info *ri;
        ri = *((struct mptfc_rport_info **)rport->dd_data);
+       pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+       nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
        dfcprintk ((MYIOC_s_INFO_FMT
                "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
                "CurrentTargetID %d, %x %llx %llx\n",
                sdev->host->host_no,
                vtarget->num_luns,
                sdev->id, ri->pg0.CurrentTargetID,
-               ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN));
+               ri->pg0.PortIdentifier,
+               (unsigned long long)pn,
+               (unsigned long long)nn));
        }
 #endif
 
                done(SCpnt);
                return 0;
        }
+
+       /* dd_data is null until finished adding target */
        ri = *((struct mptfc_rport_info **)rport->dd_data);
-       if (unlikely(ri->remap_needed))
-               return SCSI_MLQUEUE_HOST_BUSY;
+       if (unlikely(!ri)) {
+               dfcprintk ((MYIOC_s_INFO_FMT
+                       "mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
+                       ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
+                       ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
+                       SCpnt->device->id,SCpnt->device->lun));
+               SCpnt->result = DID_IMM_RETRY << 16;
+               done(SCpnt);
+               return 0;
+       }
 
-       return mptscsih_qcmd(SCpnt,done);
+       err = mptscsih_qcmd(SCpnt,done);
+#ifdef DMPT_DEBUG_FC
+       if (unlikely(err)) {
+               dfcprintk ((MYIOC_s_INFO_FMT
+                       "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n",
+                       ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
+                       ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
+                       SCpnt->device->id,SCpnt->device->lun));
+       }
+#endif
+       return err;
 }
 
 static void
        MPT_ADAPTER             *ioc = (MPT_ADAPTER *)arg;
        int                     ii;
        int                     work_to_do;
+       u64                     pn;
        unsigned long           flags;
        struct mptfc_rport_info *ri;
 
        do {
                /* start by tagging all ports as missing */
-               spin_lock_irqsave(&ioc->fc_rport_lock,flags);
                list_for_each_entry(ri, &ioc->fc_rports, list) {
                        if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
                                ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
                        }
                }
-               spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
 
                /*
                 * now rescan devices known to adapter,
                }
 
                /* delete devices still missing */
-               spin_lock_irqsave(&ioc->fc_rport_lock, flags);
                list_for_each_entry(ri, &ioc->fc_rports, list) {
                        /* if newly missing, delete it */
-                       if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
-                                         MPT_RPORT_INFO_FLAGS_MISSING))
-                         == (MPT_RPORT_INFO_FLAGS_REGISTERED |
-                             MPT_RPORT_INFO_FLAGS_MISSING)) {
+                       if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
 
                                ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
                                               MPT_RPORT_INFO_FLAGS_MISSING);
-                               ri->remap_needed = 1;
-                               fc_remote_port_delete(ri->rport);
-                               /*
-                                * remote port not really deleted 'cause
-                                * binding is by WWPN and driver only
-                                * registers FCP_TARGETs but cannot trust
-                                * data structures.
-                                */
+                               fc_remote_port_delete(ri->rport);       /* won't sleep */
                                ri->rport = NULL;
+
+                               pn = (u64)ri->pg0.WWPN.High << 32 |
+                                    (u64)ri->pg0.WWPN.Low;
                                dfcprintk ((MYIOC_s_INFO_FMT
                                        "mptfc_rescan.%d: %llx deleted\n",
                                        ioc->name,
                                        ioc->sh->host_no,
-                                       ri->pg0.WWPN));
+                                       (unsigned long long)pn));
                        }
                }
-               spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
 
                /*
                 * allow multiple passes as target state
                goto out_mptfc_probe;
        }
 
-       for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
-               mptfc_init_host_attr(ioc,ii);
-               mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
-       }
+       /* initialize workqueue */
+
+       snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d",
+               sh->host_no);
+       ioc->fc_rescan_work_q =
+               create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
+       if (!ioc->fc_rescan_work_q)
+               goto out_mptfc_probe;
+
+       /*
+        * scan for rports -
+        *      by doing it via the workqueue, some locking is eliminated
+        */
+
+       ioc->fc_rescan_work_count = 1;
+       queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
+       flush_workqueue(ioc->fc_rescan_work_q);
 
        return 0;
 
 static void __devexit
 mptfc_remove(struct pci_dev *pdev)
 {
-       MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
-       struct mptfc_rport_info *p, *n;
+       MPT_ADAPTER             *ioc = pci_get_drvdata(pdev);
+       struct mptfc_rport_info *p, *n;
+       struct workqueue_struct *work_q;
+       unsigned long           flags;
+
+       /* destroy workqueue */
+       if ((work_q=ioc->fc_rescan_work_q)) {
+               spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+               ioc->fc_rescan_work_q = NULL;
+               spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+               destroy_workqueue(work_q);
+       }
 
        fc_remove_host(ioc->sh);
 
 
 
                case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
                        /* Spoof to SCSI Selection Timeout! */
-                       sc->result = DID_NO_CONNECT << 16;
+                       if (ioc->bus_type != FC)
+                               sc->result = DID_NO_CONNECT << 16;
+                       /* else fibre, just stall until rescan event */
+                       else
+                               sc->result = DID_REQUEUE << 16;
 
                        if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
                                hd->sel_timeout[pScsiReq->TargetID]++;
 mptscsih_abort(struct scsi_cmnd * SCpnt)
 {
        MPT_SCSI_HOST   *hd;
-       MPT_ADAPTER     *ioc;
        MPT_FRAME_HDR   *mf;
        u32              ctx2abort;
        int              scpnt_idx;
                return FAILED;
        }
 
-       ioc = hd->ioc;
-       if (hd->resetPending) {
-               return FAILED;
-       }
-
-       if (hd->timeouts < -1)
-               hd->timeouts++;
-
        /* Find this command
         */
        if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
                return SUCCESS;
        }
 
+       if (hd->resetPending) {
+               return FAILED;
+       }
+
+       if (hd->timeouts < -1)
+               hd->timeouts++;
+
        printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
               hd->ioc->name, SCpnt);
        scsi_print_command(SCpnt);
        vdev = SCpnt->device->hostdata;
        retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
                vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
-               ctx2abort, mptscsih_get_tm_timeout(ioc));
+               ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
 
        printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
                hd->ioc->name,
 
                /* 7. FC: Rescan for blocked rports which might have returned.
                 */
-               else if (ioc->bus_type == FC) {
-                       int work_count;
-                       unsigned long flags;
-
+               if (ioc->bus_type == FC) {
                        spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
-                       work_count = ++ioc->fc_rescan_work_count;
+                       if (ioc->fc_rescan_work_q) {
+                               if (ioc->fc_rescan_work_count++ == 0) {
+                                       queue_work(ioc->fc_rescan_work_q,
+                                                  &ioc->fc_rescan_work);
+                               }
+                       }
                        spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
-                       if (work_count == 1)
-                               schedule_work(&ioc->fc_rescan_work);
                }
                dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
 
 {
        MPT_SCSI_HOST *hd;
        u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
-       int work_count;
        unsigned long flags;
 
        devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
 
        case MPI_EVENT_RESCAN:                          /* 06 */
                spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
-               work_count = ++ioc->fc_rescan_work_count;
+               if (ioc->fc_rescan_work_q) {
+                       if (ioc->fc_rescan_work_count++ == 0) {
+                               queue_work(ioc->fc_rescan_work_q,
+                                          &ioc->fc_rescan_work);
+                       }
+               }
                spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
-               if (work_count == 1)
-                       schedule_work(&ioc->fc_rescan_work);
                break;
 
                /*