📄 mptctl.c
字号:
} else if (iocstat == MPI_IOCSTATUS_BUSY) { printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name); printk(KERN_WARNING MYNAM ": (try again later?)\n"); return -EBUSY; } else { printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n", iocp->name, iocstat); printk(KERN_WARNING MYNAM ": (bad VooDoo)\n"); return -ENOMSG; } return 0;fwdl_out: kfree_sgl(sgl, sgl_dma, buflist, iocp); return ret;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * SGE Allocation routine * * Inputs: bytes - number of bytes to be transferred * sgdir - data direction * sge_offset - offset (in bytes) from the start of the request * frame to the first SGE * ioc - pointer to the mptadapter * Outputs: frags - number of scatter gather elements * blp - point to the buflist pointer * sglbuf_dma - pointer to the (dma) sgl * Returns: Null if failes * pointer to the (virtual) sgl if successful. */static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc){ MptSge_t *sglbuf = NULL; /* pointer to array of SGE */ /* and chain buffers */ struct buflist *buflist = NULL; /* kernel routine */ MptSge_t *sgl; int numfrags = 0; int fragcnt = 0; int alloc_sz = min(bytes,MAX_KMALLOC_SZ); // avoid kernel warning msg! int bytes_allocd = 0; int this_alloc; dma_addr_t pa; // phys addr int i, buflist_ent; int sg_spill = MAX_FRAGS_SPILL1; int dir; /* initialization */ *frags = 0; *blp = NULL; /* Allocate and initialize an array of kernel * structures for the SG elements. */ i = MAX_SGL_BYTES / 8; buflist = kmalloc(i, GFP_USER); if (buflist == NULL) return NULL; memset(buflist, 0, i); buflist_ent = 0; /* Allocate a single block of memory to store the sg elements and * the chain buffers. The calling routine is responsible for * copying the data in this array into the correct place in the * request and chain buffers. */ sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma); if (sglbuf == NULL) goto free_and_fail; if (sgdir & 0x04000000) dir = PCI_DMA_TODEVICE; else dir = PCI_DMA_FROMDEVICE; /* At start: * sgl = sglbuf = point to beginning of sg buffer * buflist_ent = 0 = first kernel structure * sg_spill = number of SGE that can be written before the first * chain element. * */ sgl = sglbuf; sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1; while (bytes_allocd < bytes) { this_alloc = min(alloc_sz, bytes-bytes_allocd); buflist[buflist_ent].len = this_alloc; buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev, this_alloc, &pa); if (buflist[buflist_ent].kptr == NULL) { alloc_sz = alloc_sz / 2; if (alloc_sz == 0) { printk(KERN_WARNING MYNAM "-SG: No can do - " "not enough memory! :-(\n"); printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", numfrags); goto free_and_fail; } continue; } else { dma_addr_t dma_addr; bytes_allocd += this_alloc; sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc); dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); sgl->Address = dma_addr; fragcnt++; numfrags++; sgl++; buflist_ent++; } if (bytes_allocd >= bytes) break; /* Need to chain? */ if (fragcnt == sg_spill) { printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required! :-(\n"); printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags); goto free_and_fail; } /* overflow check... */ if (numfrags*8 > MAX_SGL_BYTES){ /* GRRRRR... */ printk(KERN_WARNING MYNAM "-SG: No can do - " "too many SG frags! :-(\n"); printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", numfrags); goto free_and_fail; } } /* Last sge fixup: set LE+eol+eob bits */ sgl[-1].FlagsLength |= 0xC1000000; *frags = numfrags; *blp = buflist; dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " "%d SG frags generated!\n", numfrags)); dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " "last (big) alloc_sz=%d\n", alloc_sz)); return sglbuf;free_and_fail: if (sglbuf != NULL) { int i; for (i = 0; i < numfrags; i++) { dma_addr_t dma_addr; u8 *kptr; int len; if ((sglbuf[i].FlagsLength >> 24) == 0x30) continue; dma_addr = sglbuf[i].Address; kptr = buflist[i].kptr; len = buflist[i].len; pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); } pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma); } kfree(buflist); return NULL;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * Routine to free the SGL elements. */static voidkfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc){ MptSge_t *sg = sgl; struct buflist *bl = buflist; u32 nib; int dir; int n = 0; if (sg->FlagsLength & 0x04000000) dir = PCI_DMA_TODEVICE; else dir = PCI_DMA_FROMDEVICE; nib = (sg->FlagsLength & 0xF0000000) >> 28; while (! (nib & 0x4)) { /* eob */ /* skip ignore/chain. */ if (nib == 0 || nib == 3) { ; } else if (sg->Address) { dma_addr_t dma_addr; void *kptr; int len; dma_addr = sg->Address; kptr = bl->kptr; len = bl->len; pci_unmap_single(ioc->pcidev, dma_addr, len, dir); pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); n++; } sg++; bl++; nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28; } /* we're at eob! */ if (sg->Address) { dma_addr_t dma_addr; void *kptr; int len; dma_addr = sg->Address; kptr = bl->kptr; len = bl->len; pci_unmap_single(ioc->pcidev, dma_addr, len, dir); pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); n++; } pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma); kfree(buflist); dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptctl_getiocinfo - Query the host adapter for IOC information. * @arg: User space argument * * Outputs: None. * Return: 0 if successful * -EFAULT if data unavailable * -ENODEV if no such device/adapter */static intmptctl_getiocinfo (unsigned long arg, unsigned int data_size){ struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_iocinfo *karg; MPT_ADAPTER *ioc; struct pci_dev *pdev; struct Scsi_Host *sh; MPT_SCSI_HOST *hd; int iocnum; int numDevices = 0; unsigned int max_id; int ii; int port; int cim_rev; u8 revision; dctlprintk((": mptctl_getiocinfo called.\n")); /* Add of PCI INFO results in unaligned access for * IA64 and Sparc. Reset long to int. Return no PCI * data for obsolete format. */ if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev0)) cim_rev = 0; else if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev1)) cim_rev = 1; else if (data_size == sizeof(struct mpt_ioctl_iocinfo)) cim_rev = 2; else if (data_size == (sizeof(struct mpt_ioctl_iocinfo_rev0)+12)) cim_rev = 0; /* obsolete */ else return -EFAULT; karg = kmalloc(data_size, GFP_KERNEL); if (karg == NULL) { printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n", __FILE__, __LINE__); return -ENOMEM; } if (copy_from_user(karg, uarg, data_size)) { printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " "Unable to read in mpt_ioctl_iocinfo struct @ %p\n", __FILE__, __LINE__, uarg); kfree(karg); return -EFAULT; } if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); kfree(karg); return -ENODEV; } /* Verify the data transfer size is correct. * Ignore the port setting. */ if (karg->hdr.maxDataSize != data_size) { printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " "Structure size mismatch. Command not completed.\n", __FILE__, __LINE__); kfree(karg); return -EFAULT; } /* Fill in the data and return the structure to the calling * program */ if (ioc->bus_type == FC) karg->adapterType = MPT_IOCTL_INTERFACE_FC; else karg->adapterType = MPT_IOCTL_INTERFACE_SCSI; port = karg->hdr.port; karg->port = port; pdev = (struct pci_dev *) ioc->pcidev; karg->pciId = pdev->device; pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); karg->hwRev = revision; karg->subSystemDevice = pdev->subsystem_device; karg->subSystemVendor = pdev->subsystem_vendor; if (cim_rev == 1) { /* Get the PCI bus, device, and function numbers for the IOC */ karg->pciInfo.u.bits.busNumber = pdev->bus->number; karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn ); karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); } else if (cim_rev == 2) { /* Get the PCI bus, device, function and segment ID numbers for the IOC */ karg->pciInfo.u.bits.busNumber = pdev->bus->number; karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn ); karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); karg->pciInfo.segmentID = pci_domain_nr(pdev->bus); } /* Get number of devices */ if ((sh = ioc->sh) != NULL) { /* sh->max_id = maximum target ID + 1 */ max_id = sh->max_id - 1; hd = (MPT_SCSI_HOST *) sh->hostdata; /* Check all of the target structures and * keep a counter. */ if (hd && hd->Targets) { for (ii = 0; ii <= max_id; ii++) { if (hd->Targets[ii]) numDevices++; } } } karg->numDevices = numDevices; /* Set the BIOS and FW Version */ karg->FWVersion = ioc->facts.FWVersion.Word; karg->BIOSVersion = ioc->biosVersion; /* Set the Version Strings. */ strncpy (karg->driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); karg->driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0'; karg->busChangeEvent = 0; karg->hostId = ioc->pfacts[port].PortSCSIID; karg->rsvd[0] = karg->rsvd[1] = 0; /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, karg, data_size)) { printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " "Unable to write out mpt_ioctl_iocinfo struct @ %p\n", __FILE__, __LINE__, uarg); kfree(karg); return -EFAULT; } kfree(karg); return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptctl_gettargetinfo - Query the host adapter for target information. * @arg: User space argument * * Outputs: None. * Return: 0 if successful * -EFAULT if data unavailable * -ENODEV if no such device/adapter */static intmptctl_gettargetinfo (unsigned long arg){ struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_targetinfo karg; MPT_ADAPTER *ioc; struct Scsi_Host *sh; MPT_SCSI_HOST *hd; VirtDevice *vdev; char *pmem; int *pdata; IOCPage2_t *pIoc2; IOCPage3_t *pIoc3; int iocnum; int numDevices = 0; unsigned int max_id; int id, jj, indexed_lun, lun_index; u32 lun; int maxWordsLeft; int numBytes; u8 port, devType, bus_id; dctlprintk(("mptctl_gettargetinfo called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " "Unable to read in mpt_ioctl_targetinfo struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; } if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } /* Get the port number and set the maximum number of bytes * in the returned structure. * Ignore the port setting. */ numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header); maxWordsLeft = numBytes/sizeof(int); port = karg.hdr.port; if (maxWordsLeft <= 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -