|
@@ -355,15 +355,13 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
|
|
|
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 */
|
|
@@ -373,11 +371,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
|
|
|
}
|
|
|
}
|
|
|
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);
|
|
|
}
|
|
|
|
|
@@ -387,14 +383,11 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
|
|
|
/* 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,
|
|
@@ -406,16 +399,20 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
|
|
|
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));
|
|
@@ -425,8 +422,6 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
|
|
|
ri = NULL;
|
|
|
}
|
|
|
}
|
|
|
- spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
|
|
|
-
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -476,7 +471,6 @@ mptfc_target_alloc(struct scsi_target *starget)
|
|
|
vtarget->target_id = ri->pg0.CurrentTargetID;
|
|
|
vtarget->bus_id = ri->pg0.CurrentBus;
|
|
|
ri->starget = starget;
|
|
|
- ri->remap_needed = 0;
|
|
|
rc = 0;
|
|
|
}
|
|
|
}
|
|
@@ -502,10 +496,10 @@ mptfc_slave_alloc(struct scsi_device *sdev)
|
|
|
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;
|
|
@@ -519,10 +513,8 @@ mptfc_slave_alloc(struct scsi_device *sdev)
|
|
|
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) {
|
|
@@ -535,14 +527,16 @@ mptfc_slave_alloc(struct scsi_device *sdev)
|
|
|
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",
|
|
@@ -550,7 +544,9 @@ mptfc_slave_alloc(struct scsi_device *sdev)
|
|
|
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
|
|
|
|
|
@@ -570,11 +566,31 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
|
|
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
|
|
@@ -615,18 +631,17 @@ mptfc_rescan_devices(void *arg)
|
|
|
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,
|
|
@@ -639,33 +654,24 @@ mptfc_rescan_devices(void *arg)
|
|
|
}
|
|
|
|
|
|
/* 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
|
|
@@ -870,10 +876,23 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
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;
|
|
|
|
|
@@ -949,8 +968,18 @@ mptfc_init(void)
|
|
|
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);
|
|
|
|