📄 mptbase.c
字号:
/* Put Request back on FreeQ! */ spin_lock_irqsave(&ioc->FreeQlock, flags); list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);#ifdef MFCNT ioc->mfcnt--;#endif spin_unlock_irqrestore(&ioc->FreeQlock, flags);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mpt_add_sge - Place a simple SGE at address pAddr. * @pAddr: virtual address for SGE * @flagslength: SGE flags and data transfer length * @dma_addr: Physical address * * This routine places a MPT request frame back on the MPT adapter's * FreeQ. */voidmpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr){ if (sizeof(dma_addr_t) == sizeof(u64)) { SGESimple64_t *pSge = (SGESimple64_t *) pAddr; u32 tmp = dma_addr & 0xFFFFFFFF; pSge->FlagsLength = cpu_to_le32(flagslength); pSge->Address.Low = cpu_to_le32(tmp); tmp = (u32) ((u64)dma_addr >> 32); pSge->Address.High = cpu_to_le32(tmp); } else { SGESimple32_t *pSge = (SGESimple32_t *) pAddr; pSge->FlagsLength = cpu_to_le32(flagslength); pSge->Address = cpu_to_le32(dma_addr); }}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mpt_send_handshake_request - Send MPT request via doorbell * handshake method. * @handle: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. * * This routine is used exclusively to send MptScsiTaskMgmt * requests since they are required to be sent via doorbell handshake. * * NOTE: It is the callers responsibility to byte-swap fields in the * request which are greater than 1 byte in size. * * Returns 0 for success, non-zero for failure. */intmpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag){ int r = 0; u8 *req_as_bytes; int ii; /* State is known to be good upon entering * this function so issue the bus reset * request. */ /* * Emulate what mpt_put_msg_frame() does /wrt to sanity * setting cb_idx/req_idx. But ONLY if this request * is in proper (pre-alloc'd) request buffer range... */ ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req); if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; } /* Make sure there are no doorbells */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); CHIPREG_WRITE32(&ioc->chip->Doorbell, ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); /* Wait for IOC doorbell int */ if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) { return ii; } /* Read doorbell and check for active bit */ if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) return -5; dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", ioc->name, ii)); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { return -2; } /* Send request via doorbell handshake */ req_as_bytes = (u8 *) req; for (ii = 0; ii < reqBytes/4; ii++) { u32 word; word = ((req_as_bytes[(ii*4) + 0] << 0) | (req_as_bytes[(ii*4) + 1] << 8) | (req_as_bytes[(ii*4) + 2] << 16) | (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&ioc->chip->Doorbell, word); if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { r = -3; break; } } if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0) r = 0; else r = -4; /* Make sure there are no doorbells */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); return r;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mpt_verify_adapter - Given a unique IOC identifier, set pointer to * the associated MPT adapter structure. * @iocid: IOC unique identifier (integer) * @iocpp: Pointer to pointer to IOC adapter * * Returns iocid and sets iocpp. */intmpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp){ MPT_ADAPTER *ioc; list_for_each_entry(ioc,&ioc_list,list) { if (ioc->id == iocid) { *iocpp =ioc; return iocid; } } *iocpp = NULL; return -1;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptbase_probe - Install a PCI intelligent MPT adapter. * @pdev: Pointer to pci_dev structure * * This routine performs all the steps necessary to bring the IOC of * a MPT adapter to a OPERATIONAL state. This includes registering * memory regions, registering the interrupt, and allocating request * and reply memory pools. * * This routine also pre-fetches the LAN MAC address of a Fibre Channel * MPT adapter. * * Returns 0 for success, non-zero for failure. * * TODO: Add support for polled controllers */static int __devinitmptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id){ MPT_ADAPTER *ioc; u8 __iomem *mem; unsigned long mem_phys; unsigned long port; u32 msize; u32 psize; int ii; int r = -ENODEV; u64 mask = 0xffffffffffffffffULL; u8 revision; u8 pcixcmd; static int mpt_ids = 0;#ifdef CONFIG_PROC_FS struct proc_dir_entry *dent, *ent;#endif if (pci_enable_device(pdev)) return r; dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n")); if (!pci_set_dma_mask(pdev, mask)) { dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); } else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) { printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); return r; } if (!pci_set_consistent_dma_mask(pdev, mask)) dprintk((KERN_INFO MYNAM ": Using 64 bit consistent mask\n")); else dprintk((KERN_INFO MYNAM ": Not using 64 bit consistent mask\n")); ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); if (ioc == NULL) { printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); return -ENOMEM; } memset(ioc, 0, sizeof(MPT_ADAPTER)); ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->pcidev = pdev; ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); /* Initialize the event logging. */ ioc->eventTypes = 0; /* None */ ioc->eventContext = 0; ioc->eventLogSize = 0; ioc->events = NULL;#ifdef MFCNT ioc->mfcnt = 0;#endif ioc->cached_fw = NULL; /* Initilize SCSI Config Data structure */ memset(&ioc->spi_data, 0, sizeof(ScsiCfgData)); /* Initialize the running configQ head. */ INIT_LIST_HEAD(&ioc->configQ); /* Find lookup slot. */ INIT_LIST_HEAD(&ioc->list); ioc->id = mpt_ids++; mem_phys = msize = 0; port = psize = 0; for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { /* Get I/O space! */ port = pci_resource_start(pdev, ii); psize = pci_resource_len(pdev,ii); } else { /* Get memmap */ mem_phys = pci_resource_start(pdev, ii); msize = pci_resource_len(pdev,ii); break; } } ioc->mem_size = msize; if (ii == DEVICE_COUNT_RESOURCE) { printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n"); kfree(ioc); return -EINVAL; } dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); mem = NULL; /* Get logical ptr for PciMem0 space */ /*mem = ioremap(mem_phys, msize);*/ mem = ioremap(mem_phys, 0x100); if (mem == NULL) { printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n"); kfree(ioc); return -EINVAL; } ioc->memmap = mem; dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", &ioc->facts, &ioc->pfacts[0])); ioc->mem_phys = mem_phys; ioc->chip = (SYSIF_REGS __iomem *)mem; /* Save Port IO values in case we need to do downloadboot */ { u8 *pmem = (u8*)port; ioc->pio_mem_phys = port; ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; } if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) { ioc->prod_name = "LSIFC909"; ioc->bus_type = FC; } if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { ioc->prod_name = "LSIFC929"; ioc->bus_type = FC; } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) { ioc->prod_name = "LSIFC919"; ioc->bus_type = FC; } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) { pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); ioc->bus_type = FC; if (revision < XL_929) { ioc->prod_name = "LSIFC929X"; /* 929X Chip Fix. Set Split transactions level * for PCIX. Set MOST bits to zero. */ pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); } else { ioc->prod_name = "LSIFC929XL"; /* 929XL Chip Fix. Set MMRBC to 0x08. */ pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd |= 0x08; pci_write_config_byte(pdev, 0x6a, pcixcmd); } } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) { ioc->prod_name = "LSIFC919X"; ioc->bus_type = FC; /* 919X Chip Fix. Set Split transactions level * for PCIX. Set MOST bits to zero. */ pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { ioc->prod_name = "LSI53C1030"; ioc->bus_type = SCSI; /* 1030 Chip Fix. Disable Split transactions * for PCIX. Set MOST bits to zero if Rev < C0( = 8). */ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); if (revision < C0_1030) { pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); } } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) { ioc->prod_name = "LSI53C1035"; ioc->bus_type = SCSI; } sprintf(ioc->name, "ioc%d", ioc->id); spin_lock_init(&ioc->FreeQlock); /* Disable all! */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); /* Set lookup ptr. */ list_add_tail(&ioc->list, &ioc_list); ioc->pci_irq = -1; if (pdev->irq) { r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc); if (r < 0) {#ifndef __sparc__ printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n", ioc->name, pdev->irq);#else printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", ioc->name, __irq_itoa(pdev->irq));#endif list_del(&ioc->list); iounmap(mem); kfree(ioc); return -EBUSY; } ioc->pci_irq = pdev->irq; pci_set_master(pdev); /* ?? */ pci_set_drvdata(pdev, ioc);#ifndef __sparc__ dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));#else dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));#endif } /* NEW! 20010220 -sralston * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. */ mpt_detect_bound_ports(ioc, pdev); if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n", ioc->name, r); list_del(&ioc->list); free_irq(ioc->pci_irq, ioc); iounmap(mem); kfree(ioc); pci_set_drvdata(pdev, NULL); return r; } /* call per device driver probe entry point */ for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) { if(MptDeviceDriverHandlers[ii] && MptDeviceDriverHandlers[ii]->probe) { MptDeviceDriverHandlers[ii]->probe(pdev,id); } }#ifdef CONFIG_PROC_FS /* * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. */ dent = proc_mkdir(ioc->name, mpt_proc_root_dir); if (dent) { ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent); if (ent) { ent->read_proc = procmpt_iocinfo_read; ent->data = ioc; } ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent); if (ent) { ent->read_proc = procmpt_summary_read; ent->data = ioc; } }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -