static struct scsi_transport_template *mptfc_transport_template = NULL;
-static struct fc_function_template mptfc_transport_functions = {
+struct fc_function_template mptfc_transport_functions = {
.dd_fcrport_size = 8,
.show_host_node_name = 1,
.show_host_port_name = 1,
rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
rid->port_id = pg0->PortIdentifier;
rid->roles = FC_RPORT_ROLE_UNKNOWN;
+ rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
+ if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
+ rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
return 0;
}
+static void
+mptfc_remap_sdev(struct scsi_device *sdev, void *arg)
+{
+ VirtDevice *vdev;
+ VirtTarget *vtarget;
+ struct scsi_target *starget;
+
+ starget = scsi_target(sdev);
+ if (starget->hostdata == arg) {
+ vtarget = arg;
+ vdev = sdev->hostdata;
+ if (vdev) {
+ vdev->bus_id = vtarget->bus_id;
+ vdev->target_id = vtarget->target_id;
+ }
+ }
+}
+
static void
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, nn;
+ u64 pn;
+ unsigned long flags;
VirtTarget *vtarget;
- u32 roles = FC_RPORT_ROLE_UNKNOWN;
if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
return;
- roles |= FC_RPORT_ROLE_FCP_TARGET;
- if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
- roles |= FC_RPORT_ROLE_FCP_INITIATOR;
-
/* 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,
if (vtarget) {
vtarget->target_id = pg0->CurrentTargetID;
vtarget->bus_id = pg0->CurrentBus;
+ starget_for_each_device(ri->starget,
+ vtarget,mptfc_remap_sdev);
}
+ ri->remap_needed = 0;
}
- *((struct mptfc_rport_info **)rport->dd_data) = ri;
- /* scan will be scheduled once rport becomes a target */
- fc_remote_port_rolechg(rport,roles);
-
- 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,
+ oc->sh->host_no,
pg0->PortIdentifier,
- (unsigned long long)nn,
- (unsigned long long)pn,
+ pg0->WWNN,
+ pg0->WWPN,
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;
}
}
* Return non-zero if allocation fails.
* Init memory once per LUN.
*/
-static int
+int
mptfc_slave_alloc(struct scsi_device *sdev)
{
MPT_SCSI_HOST *hd;
VirtDevice *vdev;
struct scsi_target *starget;
struct fc_rport *rport;
+ unsigned long flags;
- starget = scsi_target(sdev);
- rport = starget_to_rport(starget);
+ rport = starget_to_rport(scsi_target(sdev));
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->ioc_id = hd->ioc->id;
vdev->lun = sdev->lun;
+ vdev->target_id = vtarget->target_id;
+ vdev->bus_id = vtarget->bus_id;
- vtarget->num_luns++;
+ 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",
- hd->ioc->name,
+ ioc->name,
sdev->host->host_no,
vtarget->num_luns,
sdev->id, ri->pg0.CurrentTargetID,
- ri->pg0.PortIdentifier,
- (unsigned long long)pn,
- (unsigned long long)nn));
- }
-#endif
+ ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN));
return 0;
}
done(SCpnt);
return 0;
}
-
- /* dd_data is null until finished adding target */
ri = *((struct mptfc_rport_info **)rport->dd_data);
- 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;
- }
+ if (unlikely(ri->remap_needed))
+ return SCSI_MLQUEUE_HOST_BUSY;
- 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;
+ return mptscsih_qcmd(SCpnt,done);
}
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_MISSING) {
+ if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
+ MPT_RPORT_INFO_FLAGS_MISSING))
+ == (MPT_RPORT_INFO_FLAGS_REGISTERED |
+ MPT_RPORT_INFO_FLAGS_MISSING)) {
ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
MPT_RPORT_INFO_FLAGS_MISSING);
- fc_remote_port_delete(ri->rport); /* won't sleep */
+ 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.
+ */
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,
- (unsigned long long)pn));
+ ri->pg0.WWPN));
}
}
+ spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
/*
* allow multiple passes as target state
goto out_mptfc_probe;
}
- /* 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);
+ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+ mptfc_init_host_attr(ioc,ii);
+ mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+ }
return 0;
mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
if (mpt_event_register(mptfcDoneCtx, mptscsih_event_process) == 0) {
- devtverboseprintk((KERN_INFO MYNAM
+ devtprintk((KERN_INFO MYNAM
": Registered for IOC event notifications\n"));
}
static void __devexit
mptfc_remove(struct pci_dev *pdev)
{
- 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);
- }
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+ struct mptfc_rport_info *p, *n;
fc_remove_host(ioc->sh);