X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmessage%2Ffusion%2Fmptfc.c;h=c3a3499bce2ae8c3ece665ce11f98b6027a1cd83;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=856487741ef43b0f2458e6dc6bc55a2edc354fa1;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 856487741..c3a3499bc 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -154,7 +154,7 @@ MODULE_DEVICE_TABLE(pci, mptfc_pci_table); 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, @@ -341,10 +341,31 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid) 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) { @@ -352,18 +373,15 @@ 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 */ @@ -373,9 +391,11 @@ 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); } @@ -385,11 +405,14 @@ 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, @@ -400,22 +423,19 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) 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)); @@ -425,6 +445,8 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) ri = NULL; } } + spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); + } /* @@ -474,6 +496,7 @@ 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; } } @@ -491,7 +514,7 @@ mptfc_target_alloc(struct scsi_target *starget) * 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; @@ -499,10 +522,10 @@ mptfc_slave_alloc(struct scsi_device *sdev) 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; @@ -516,8 +539,10 @@ 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) { @@ -528,30 +553,23 @@ mptfc_slave_alloc(struct scsi_device *sdev) } 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; } @@ -569,31 +587,11 @@ 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)) { - 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 @@ -634,17 +632,18 @@ 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, @@ -657,24 +656,33 @@ 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_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 @@ -879,23 +887,10 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) 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; @@ -946,7 +941,7 @@ mptfc_init(void) 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")); } @@ -971,18 +966,8 @@ 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; - 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);