Example #1
0
/**
 * lpfc_reg_rpi - Prepare a mailbox command for registering remote login
 * @phba: pointer to lpfc hba data structure.
 * @vpi: virtual N_Port identifier.
 * @did: remote port identifier.
 * @param: pointer to memory holding the server parameters.
 * @pmb: pointer to the driver internal queue element for mailbox command.
 * @flag: action flag to be passed back for the complete function.
 *
 * The registration login mailbox command is used to register an N_Port or
 * F_Port login. This registration allows the HBA to cache the remote N_Port
 * service parameters internally and thereby make the appropriate FC-2
 * decisions. The remote port service parameters are handed off by the driver
 * to the HBA using a descriptor entry that directly identifies a buffer in
 * host memory. In exchange, the HBA returns an RPI identifier.
 *
 * This routine prepares the mailbox command for registering remote port login.
 * The function allocates DMA buffer for passing the service parameters to the
 * HBA with the mailbox command.
 *
 * Return codes
 *    0 - Success
 *    1 - DMA memory allocation failed
 **/
int
lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
	       uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
{
	MAILBOX_t *mb = &pmb->u.mb;
	uint8_t *sparam;
	struct lpfc_dmabuf *mp;

	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));

	mb->un.varRegLogin.rpi = 0;
	if (phba->sli_rev == LPFC_SLI_REV4) {
		mb->un.varRegLogin.rpi = lpfc_sli4_alloc_rpi(phba);
		if (mb->un.varRegLogin.rpi == LPFC_RPI_ALLOC_ERROR)
			return 1;
	}

	mb->un.varRegLogin.vpi = vpi + phba->vpi_base;
	mb->un.varRegLogin.did = did;
	mb->un.varWords[30] = flag;	/* Set flag to issue action on cmpl */

	mb->mbxOwner = OWN_HOST;

	/* Get a buffer to hold NPorts Service Parameters */
	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
	if (mp)
		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
	if (!mp || !mp->virt) {
		kfree(mp);
		mb->mbxCommand = MBX_REG_LOGIN64;
		/* REG_LOGIN: no buffers */
		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
				"0302 REG_LOGIN: no buffers, VPI:%d DID:x%x, "
				"flag x%x\n", vpi, did, flag);
		return (1);
	}
	INIT_LIST_HEAD(&mp->list);
	sparam = mp->virt;

	/* Copy param's into a new buffer */
	memcpy(sparam, param, sizeof (struct serv_parm));

	/* save address for completion */
	pmb->context1 = (uint8_t *) mp;

	mb->mbxCommand = MBX_REG_LOGIN64;
	mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
	mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys);
	mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys);

	return (0);
}
Example #2
0
int
lpfc_reg_login(struct lpfc_hba * phba,
	       uint32_t did, uint8_t * param, LPFC_MBOXQ_t * pmb, uint32_t flag)
{
	uint8_t *sparam;
	struct lpfc_dmabuf *mp;
	MAILBOX_t *mb;
	struct lpfc_sli *psli;

	psli = &phba->sli;
	mb = &pmb->mb;
	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));

	mb->un.varRegLogin.rpi = 0;
	mb->un.varRegLogin.did = did;
	mb->un.varWords[30] = flag;	/* Set flag to issue action on cmpl */

	mb->mbxOwner = OWN_HOST;

	/* Get a buffer to hold NPorts Service Parameters */
	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) ||
	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
		if (mp)
			kfree(mp);

		mb->mbxCommand = MBX_REG_LOGIN64;
		/* REG_LOGIN: no buffers */
		lpfc_printf_log(phba,
			       KERN_WARNING,
			       LOG_MBOX,
			       "%d:0302 REG_LOGIN: no buffers Data x%x x%x\n",
			       phba->brd_no,
			       (uint32_t) did, (uint32_t) flag);
		return (1);
	}
	INIT_LIST_HEAD(&mp->list);
	sparam = mp->virt;

	/* Copy param's into a new buffer */
	memcpy(sparam, param, sizeof (struct serv_parm));

	/* save address for completion */
	pmb->context1 = (uint8_t *) mp;

	mb->mbxCommand = MBX_REG_LOGIN64;
	mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
	mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys);
	mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys);

	return (0);
}
Example #3
0
/**
 * lpfc_dump_static_vport - Dump HBA's static vport information.
 * @phba: pointer to lpfc hba data structure.
 * @pmb: pointer to the driver internal queue element for mailbox command.
 * @offset: offset for dumping vport info.
 *
 * The dump mailbox command provides a method for the device driver to obtain
 * various types of information from the HBA device.
 *
 * This routine prepares the mailbox command for dumping list of static
 * vports to be created.
 **/
int
lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
		uint16_t offset)
{
	MAILBOX_t *mb;
	struct lpfc_dmabuf *mp;

	mb = &pmb->u.mb;

	/* Setup to dump vport info region */
	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
	mb->mbxCommand = MBX_DUMP_MEMORY;
	mb->un.varDmp.type = DMP_NV_PARAMS;
	mb->un.varDmp.entry_index = offset;
	mb->un.varDmp.region_id = DMP_REGION_VPORT;
	mb->mbxOwner = OWN_HOST;

	/* For SLI3 HBAs data is embedded in mailbox */
	if (phba->sli_rev != LPFC_SLI_REV4) {
		mb->un.varDmp.cv = 1;
		mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t);
		return 0;
	}

	/* For SLI4 HBAs driver need to allocate memory */
	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
	if (mp)
		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);

	if (!mp || !mp->virt) {
		kfree(mp);
		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
			"2605 lpfc_dump_static_vport: memory"
			" allocation failed\n");
		return 1;
	}
	memset(mp->virt, 0, LPFC_BPL_SIZE);
	INIT_LIST_HEAD(&mp->list);
	/* save address for completion */
	pmb->context2 = (uint8_t *) mp;
	mb->un.varWords[3] = putPaddrLow(mp->phys);
	mb->un.varWords[4] = putPaddrHigh(mp->phys);
	mb->un.varDmp.sli4_length = sizeof(struct static_vport_info);

	return 0;
}
Example #4
0
int
lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
	struct lpfc_dmabuf *mp;
	MAILBOX_t *mb;
	struct lpfc_sli *psli;

	psli = &phba->sli;
	mb = &pmb->mb;
	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));

	mb->mbxOwner = OWN_HOST;

	/* Get a buffer to hold the HBAs Service Parameters */

	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
		if (mp)
			kfree(mp);
		mb->mbxCommand = MBX_READ_SPARM64;
		/* READ_SPARAM: no buffers */
		lpfc_printf_log(phba,
			        KERN_WARNING,
			        LOG_MBOX,
			        "%d:0301 READ_SPARAM: no buffers\n",
			        phba->brd_no);
		return (1);
	}
	INIT_LIST_HEAD(&mp->list);
	mb->mbxCommand = MBX_READ_SPARM64;
	mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
	mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
	mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);

	/* save address for completion */
	pmb->context1 = mp;

	return (0);
}
/**
 * lpfc_config_msi: Prepare a mailbox command for configuring msi-x.
 * @phba: pointer to lpfc hba data structure.
 * @pmb: pointer to the driver internal queue element for mailbox command.
 *
 * The configure MSI-X mailbox command is used to configure the HBA's SLI-3
 * MSI-X multi-message interrupt vector association to interrupt attention
 * conditions.
 *
 * Return codes
 *    0 - Success
 *    -EINVAL - Failure
 **/
int
lpfc_config_msi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
	MAILBOX_t *mb = &pmb->mb;
	uint32_t attentionConditions[2];

	/* Sanity check */
	if (phba->cfg_use_msi != 2) {
		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
				"0475 Not configured for supporting MSI-X "
				"cfg_use_msi: 0x%x\n", phba->cfg_use_msi);
		return -EINVAL;
	}

	if (phba->sli_rev < 3) {
		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
				"0476 HBA not supporting SLI-3 or later "
				"SLI Revision: 0x%x\n", phba->sli_rev);
		return -EINVAL;
	}

	/* Clear mailbox command fields */
	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));

	/*
	 * SLI-3, Message Signaled Interrupt Fearure.
	 */

	/* Multi-message attention configuration */
	attentionConditions[0] = (HA_R0ATT | HA_R1ATT | HA_R2ATT | HA_ERATT |
				  HA_LATT | HA_MBATT);
	attentionConditions[1] = 0;

	mb->un.varCfgMSI.attentionConditions[0] = attentionConditions[0];
	mb->un.varCfgMSI.attentionConditions[1] = attentionConditions[1];

	/*
	 * Set up message number to HA bit association
	 */
#ifdef __BIG_ENDIAN_BITFIELD
	/* RA0 (FCP Ring) */
	mb->un.varCfgMSI.messageNumberByHA[HA_R0_POS] = 1;
	/* RA1 (Other Protocol Extra Ring) */
	mb->un.varCfgMSI.messageNumberByHA[HA_R1_POS] = 1;
#else   /*  __LITTLE_ENDIAN_BITFIELD */
	/* RA0 (FCP Ring) */
	mb->un.varCfgMSI.messageNumberByHA[HA_R0_POS^3] = 1;
	/* RA1 (Other Protocol Extra Ring) */
	mb->un.varCfgMSI.messageNumberByHA[HA_R1_POS^3] = 1;
#endif
	/* Multi-message interrupt autoclear configuration*/
	mb->un.varCfgMSI.autoClearHA[0] = attentionConditions[0];
	mb->un.varCfgMSI.autoClearHA[1] = attentionConditions[1];

	/* For now, HBA autoclear does not work reliably, disable it */
	mb->un.varCfgMSI.autoClearHA[0] = 0;
	mb->un.varCfgMSI.autoClearHA[1] = 0;

	/* Set command and owner bit */
	mb->mbxCommand = MBX_CONFIG_MSI;
	mb->mbxOwner = OWN_HOST;

	return 0;
}
Example #6
0
int
lpfc_process_ioctl_dfc(LPFCCMDINPUT_t * cip)
{
    struct lpfc_hba *phba;
    int rc = -1;
    uint32_t outshift;
    uint32_t total_mem;
    void   *dataout;

    if ((phba = lpfc_get_phba_by_inst(cip->lpfc_brd)) == NULL)
        return EINVAL;

    /* libdfc debug entry */
    lpfc_printf_log(phba,
                    KERN_INFO,
                    LOG_LIBDFC,
                    "%d:1600 libdfc debug entry Data: x%x x%lx x%lx x%x\n",
                    phba->brd_no, cip->lpfc_cmd,
                    (ulong) cip->lpfc_arg1,(ulong) cip->lpfc_arg2,
                    cip->lpfc_outsz);

    outshift = 0;
    if (cip->lpfc_outsz >= 4096) {

        /* Allocate memory for ioctl data. If buffer is bigger than 64k, then we
         * allocate 64k and re-use that buffer over and over to xfer the whole
         * block. This is because Linux kernel has a problem allocating more than
         * 120k of kernel space memory. Saw problem with GET_FCPTARGETMAPPING...
         */
        if (cip->lpfc_outsz <= (64 * 1024))
            total_mem = cip->lpfc_outsz;
        else
            total_mem = 64 * 1024;
    } else {
        /* Allocate memory for ioctl data */
        total_mem = 4096;
    }
    dataout = kmalloc(total_mem, GFP_KERNEL);
    if (!dataout)
        return (ENOMEM);

    switch (cip->lpfc_cmd) {

    /* Debug Interface Support - dfc */
    case LPFC_LIP:
        rc = lpfc_ioctl_lip(phba, cip, dataout);
        break;

    case LPFC_INST:
        rc = lpfc_ioctl_inst(phba, cip, dataout);
        break;

    case LPFC_READ_BPLIST:
        rc = lpfc_ioctl_read_bplist(phba, cip, dataout, total_mem);
        break;

    case LPFC_LISTN:
        rc = lpfc_ioctl_listn(phba, cip, dataout, total_mem);
        break;

    case LPFC_RESET:
        rc = lpfc_ioctl_reset(phba, cip);
        break;

    case LPFC_READ_HBA:
        rc = lpfc_ioctl_read_hba(phba, cip, dataout, total_mem);
        break;

    case LPFC_STAT:
        rc = lpfc_ioctl_stat(phba, cip, dataout);
        break;
    }

    if (rc != -1) {
        /* dfc_ioctl exit */
        lpfc_printf_log(phba,
                        KERN_INFO,
                        LOG_LIBDFC,
                        "%d:1601 libdfc debug exit Data: x%x x%x x%x\n",
                        phba->brd_no,
                        rc,
                        cip->lpfc_outsz,
                        (uint32_t) ((ulong) cip->lpfc_dataout));
    }


    /* Copy data to user space config method */
    if (rc == 0) {
        if (cip->lpfc_outsz) {
            if (copy_to_user
                    ((uint8_t *) cip->lpfc_dataout,
                     (uint8_t *) dataout, (int)cip->lpfc_outsz)) {
                rc = EIO;
            }
        }
    }


    kfree(dataout);
    return(rc);
}
Example #7
0
void
lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
	MAILBOX_t *mb = &pmb->mb;
	dma_addr_t pdma_addr;
	uint32_t bar_low, bar_high;
	size_t offset;
	HGP hgp;
	void __iomem *to_slim;

	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
	mb->mbxCommand = MBX_CONFIG_PORT;
	mb->mbxOwner = OWN_HOST;

	mb->un.varCfgPort.pcbLen = sizeof(PCB_t);

	offset = (uint8_t *)&phba->slim2p->pcb - (uint8_t *)phba->slim2p;
	pdma_addr = phba->slim2p_mapping + offset;
	mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
	mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);

	/* Now setup pcb */
	phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
	phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2;

	/* Setup Mailbox pointers */
	phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t);
	offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p;
	pdma_addr = phba->slim2p_mapping + offset;
	phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr);
	phba->slim2p->pcb.mbAddrLow = putPaddrLow(pdma_addr);

	/*
	 * Setup Host Group ring pointer.
	 *
	 * For efficiency reasons, the ring get/put pointers can be
	 * placed in adapter memory (SLIM) rather than in host memory.
	 * This allows firmware to avoid PCI reads/writes when updating
	 * and checking pointers.
	 *
	 * The firmware recognizes the use of SLIM memory by comparing
	 * the address of the get/put pointers structure with that of
	 * the SLIM BAR (BAR0).
	 *
	 * Caution: be sure to use the PCI config space value of BAR0/BAR1
	 * (the hardware's view of the base address), not the OS's
	 * value of pci_resource_start() as the OS value may be a cookie
	 * for ioremap/iomap.
	 */


	pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low);
	pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high);


	/* mask off BAR0's flag bits 0 - 3 */
	phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
					(SLIMOFF*sizeof(uint32_t));
	if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
		phba->slim2p->pcb.hgpAddrHigh = bar_high;
	else
		phba->slim2p->pcb.hgpAddrHigh = 0;
	/* write HGP data to SLIM at the required longword offset */
	memset(&hgp, 0, sizeof(HGP));
	to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t));
	lpfc_memcpy_to_slim(to_slim, &hgp, sizeof (HGP));

	/* Setup Port Group ring pointer */
	offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
		 (uint8_t *)phba->slim2p;
	pdma_addr = phba->slim2p_mapping + offset;
	phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr);
	phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr);

	/* Use callback routine to setp rings in the pcb */
	lpfc_config_pcb_setup(phba);

	/* special handling for LC HBAs */
	if (lpfc_is_LC_HBA(phba->pcidev->device)) {
		uint32_t hbainit[5];

		lpfc_hba_init(phba, hbainit);

		memcpy(&mb->un.varCfgPort.hbainit, hbainit, 20);
	}

	/* Swap PCB if needed */
	lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb,
								sizeof (PCB_t));

	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
		        "%d:0405 Service Level Interface (SLI) 2 selected\n",
		        phba->brd_no);
}