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