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;
/*