📄 mptscsih.c
字号:
if (dropCounter == DROP_THIS_CMD) { dropCounter = 0; /* If global is set, then we are already * doing something - so keep issuing commands. */ if (dropMfPtr == NULL) { dropTestNum++; dropMfPtr = mf; atomic_inc(&queue_depth); printk(MYIOC_s_INFO_FMT "Dropped SCSI cmd (%p)\n", hd->ioc->name, SCpnt); printk("mf (%p) req (%4x) tot cmds (%d)\n", mf, my_idx, numTotCmds); return 0; } } }#endif /* SCSI specific processing */ issueCmd = 1; if (hd->is_spi) { int dvStatus = hd->ioc->spi_data.dvStatus[target]; if (dvStatus || hd->ioc->spi_data.forceDv) { /* Write SDP1 on 1st I/O to this target */ if (dvStatus & MPT_SCSICFG_NEGOTIATE) { mptscsih_writeSDP1(hd, 0, target, hd->negoNvram); dvStatus &= ~MPT_SCSICFG_NEGOTIATE; hd->ioc->spi_data.dvStatus[target] = dvStatus; }#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) { unsigned long lflags; /* Schedule DV if necessary */ spin_lock_irqsave(&dvtaskQ_lock, lflags); if (!dvtaskQ_active) { dvtaskQ_active = 1; mptscsih_dvTask.sync = 0; mptscsih_dvTask.routine = mptscsih_domainValidation; mptscsih_dvTask.data = (void *) hd; SCHEDULE_TASK(&mptscsih_dvTask); } hd->ioc->spi_data.forceDv = 0; spin_unlock_irqrestore(&dvtaskQ_lock, lflags); } /* Trying to do DV to this target, extend timeout. * Wait to issue intil flag is clear */ if (dvStatus & MPT_SCSICFG_DV_PENDING) { mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); issueCmd = 0; }#endif } } if (issueCmd) { mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p)\n", hd->ioc->name, SCpnt)); } else { ddvtprintk((MYIOC_s_INFO_FMT "Pending SCSI cmd (%p)\n", hd->ioc->name, SCpnt)); /* Place this command on the pendingQ if possible */ spin_lock_irqsave(&hd->freedoneQlock, flags); if (!Q_IS_EMPTY(&hd->freeQ)) { buffer = hd->freeQ.head; Q_DEL_ITEM(buffer); /* Save the mf pointer */ buffer->argp = (void *)mf; /* Add to the pendingQ */ Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q); spin_unlock_irqrestore(&hd->freedoneQlock, flags); } else { spin_unlock_irqrestore(&hd->freedoneQlock, flags); SCpnt->result = (DID_BUS_BUSY << 16); SCpnt->scsi_done(SCpnt); } } } else { mptscsih_freeChainBuffers(hd, my_idx); mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); did_errcode = 3; goto did_error; } return 0;did_error: dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n", hd->ioc->name, did_errcode, SCpnt)); /* Just wish OS to issue a retry */ SCpnt->result = (DID_BUS_BUSY << 16); spin_lock_irqsave(&hd->freedoneQlock, flags); if (!Q_IS_EMPTY(&hd->freeQ)) { buffer = hd->freeQ.head; Q_DEL_ITEM(buffer); /* Set the Scsi_Cmnd pointer */ buffer->argp = (void *)SCpnt; /* Add to the doneQ */ Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); spin_unlock_irqrestore(&hd->freedoneQlock, flags); } else { spin_unlock_irqrestore(&hd->freedoneQlock, flags); SCpnt->scsi_done(SCpnt); } return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_Add32BitSGE - Add a 32Bit SGE (plus chain buffers) to the * SCSIIORequest_t Message Frame. * @hd: Pointer to MPT_SCSI_HOST structure * @SCpnt: Pointer to Scsi_Cmnd structure * @pReq: Pointer to SCSIIORequest_t structure * * Returns ... */static intmptscsih_Add32BitSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx){ MptSge_t *psge; MptChain_t *chainSge; struct scatterlist *sg; int frm_sz; int sges_left, sg_done; int chain_idx = MPT_HOST_NO_CHAIN; int sgeOffset; int numSgeSlots, numSgeThisFrame; u32 sgflags, sgdir, len, thisxfer = 0; int offset; int newIndex; int ii; dma_addr_t v2; sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; if (sgdir == MPI_SCSIIO_CONTROL_WRITE) { sgdir = MPT_TRANSFER_HOST_TO_IOC; } else { sgdir = MPT_TRANSFER_IOC_TO_HOST; } psge = (MptSge_t *) &pReq->SGL; frm_sz = hd->ioc->req_sz; /* Map the data portion, if any. * sges_left = 0 if no data transfer. */ sges_left = SCpnt->use_sg; if (SCpnt->use_sg) { sges_left = pci_map_sg(hd->ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); } else if (SCpnt->request_bufflen) { dma_addr_t buf_dma_addr; scPrivate *my_priv; buf_dma_addr = pci_map_single(hd->ioc->pcidev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); /* We hide it here for later unmap. */ my_priv = (scPrivate *) &SCpnt->SCp; my_priv->p1 = (void *)(ulong) buf_dma_addr; dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n", hd->ioc->name, SCpnt, SCpnt->request_bufflen)); /* 0xD1000000 = LAST | EOB | SIMPLE | EOL */ psge->FlagsLength = cpu_to_le32( 0xD1000000|sgdir|SCpnt->request_bufflen); cpu_to_leXX(buf_dma_addr, psge->Address); return SUCCESS; } /* Handle the SG case. */ sg = (struct scatterlist *) SCpnt->request_buffer; sg_done = 0; sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION); chainSge = NULL; /* Prior to entering this loop - the following must be set * current MF: sgeOffset (bytes) * chainSge (Null if original MF is not a chain buffer) * sg_done (num SGE done for this MF) */nextSGEset: numSgeSlots = ((frm_sz - sgeOffset) / sizeof(MptSge_t)); numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; /* Get first (num - 1) SG elements * Skip any SG entries with a length of 0 * NOTE: at finish, sg and psge pointed to NEXT data/location positions */ for (ii=0; ii < (numSgeThisFrame-1); ii++) { thisxfer = sg_dma_len(sg); if (thisxfer == 0) { sg ++; /* Get next SG element from the OS */ sg_done++; continue; } len += thisxfer; psge->FlagsLength = cpu_to_le32( sgflags | thisxfer ); v2 = sg_dma_address(sg); cpu_to_leXX(v2, psge->Address); sg++; /* Get next SG element from the OS */ psge++; /* Point to next SG location in this MF */ sgeOffset += sizeof(MptSge_t); sg_done++; } if (numSgeThisFrame == sges_left) { /* Add last element, end of buffer and end of list flags. */ sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT | MPT_SGE_FLAGS_END_OF_BUFFER | MPT_SGE_FLAGS_ADDRESSING | MPT_SGE_FLAGS_END_OF_LIST; /* Add last SGE and set termination flags. * Note: Last SGE may have a length of 0 - which should be ok. */ thisxfer = sg_dma_len(sg); len += thisxfer; psge->FlagsLength = cpu_to_le32( sgflags | thisxfer ); v2 = sg_dma_address(sg); cpu_to_leXX(v2, psge->Address); sg_done++; if (chainSge) { /* The current buffer is a chain buffer, * but there is not another one. * Update the chain element * Offset and Length fields. */ chainSge->NextChainOffset = 0; sgeOffset += sizeof(MptSge_t); chainSge->Length = cpu_to_le16(sgeOffset); } else { /* The current buffer is the original MF * and there is no Chain buffer. */ pReq->ChainOffset = 0; } } else { /* At least one chain buffer is needed. * Complete the first MF * - last SGE element, set the LastElement bit * - set ChainOffset (words) for orig MF * (OR finish previous MF chain buffer) * - update MFStructPtr ChainIndex * - Populate chain element * Also * Loop until done. */ dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", hd->ioc->name, sg_done)); /* Set LAST_ELEMENT flag for last non-chain element * in the buffer. Since psge points at the NEXT * SGE element, go back one SGE element, update the flags * and reset the pointer. (Note: sgflags & thisxfer are already * set properly). */ if (sg_done) { psge--; sgflags = le32_to_cpu (psge->FlagsLength); sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; psge->FlagsLength = cpu_to_le32( sgflags ); psge++; } if (chainSge) { /* The current buffer is a chain buffer. * chainSge points to the previous Chain Element. * Update its chain element Offset and Length (must * include chain element size) fields. * Old chain element is now complete. */ chainSge->NextChainOffset = (u8) (sgeOffset >> 2); sgeOffset += sizeof(MptSge_t); chainSge->Length = cpu_to_le16(sgeOffset); } else { /* The original MF buffer requires a chain buffer - * set the offset. * Last element in this MF is a chain element. */ pReq->ChainOffset = (u8) (sgeOffset >> 2); } sges_left -= sg_done; /* NOTE: psge points to the beginning of the chain element * in current buffer. Get a chain buffer. */ if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED) return FAILED; /* Update the tracking arrays. * If chainSge == NULL, update ReqToChain, else ChainToChain */ if (chainSge) { hd->ChainToChain[chain_idx] = newIndex; } else { hd->ReqToChain[req_idx] = newIndex; } chain_idx = newIndex; offset = hd->ioc->req_sz * chain_idx; /* Populate the chainSGE for the current buffer. * - Set chain buffer pointer to psge and fill * out the Address and Flags fields. */ chainSge = (MptChain_t *) psge; chainSge->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; cpu_to_leXX ((hd->ChainBufferDMA + offset), chainSge->Address); dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)", psge, req_idx)); /* Start the SGE for the next buffer */ psge = (MptSge_t *) (hd->ChainBuffer + offset); sgeOffset = 0; sg_done = 0; dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n", psge, chain_idx)); /* Start the SGE for the next buffer */ goto nextSGEset; } return SUCCESS;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_AddNullSGE - Add a NULL SGE to the SCSIIORequest_t * Message Frame. * @pReq: Pointer to SCSIIORequest_t structure */static voidmptscsih_AddNullSGE(SCSIIORequest_t *pReq){ MptSge_t *psge; psge = (MptSge_t *) &pReq->SGL; psge->FlagsLength = cpu_to_le32(MPT_SGE_FLAGS_SSIMPLE_READ | 0); cpu_to_leXX( (dma_addr_t) -1, psge->Address); return;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_getFreeChainBuffes - Function to get a free chain * from the MPT_SCSI_HOST FreeChainQ. * @hd: Pointer to the MPT_SCSI_HOST instance * @req_idx: Index of the SCSI IO request frame. (output) * * return SUCCESS or FAILED */static intmptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex){ MPT_FRAME_HDR *chainBuf = NULL; unsigned long flags; int rc = FAILED; int chain_idx = MPT_HOST_NO_CHAIN; //spin_lock_irqsave(&hd->FreeChainQlock, flags); spin_lock_irqsave(&hd->ioc->FreeQlock, flags); if (!Q_IS_EMPTY(&hd->FreeChainQ)) { int offset; chainBuf = hd->FreeChainQ.head; Q_DEL_ITEM(&chainBuf->u.frame.linkage); offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer; chain_idx = offset / hd->ioc->req_sz; rc = SUCCESS; } //spin_unlock_irqrestore(&hd->FreeChainQlock, flags); spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); *retIndex = chain_idx; dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", hd->ioc->name, *retIndex, chainBuf)); return rc;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_freeChainBuffers - Function to free chain buffers associated * with a SCSI IO request * @hd: Pointer to the MPT_SCSI_HOST instance * @req_idx: Index of the SCSI IO request frame. * * Called if SG chain buffer allocation fails and mptscsih callbacks. * No return. */static voidmptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx){ MPT_FRAME_HDR *chain = NULL; unsigned long flags; int chain_idx; int next; /* Get the first chain index and reset * tracker state. */ chain_idx = hd->ReqToChain[req_idx]; hd->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN; while (chain_idx != MPT_HOST_NO_CHAIN) { /* Save the next chain buffer index */ next = hd->ChainToChain[chain_idx]; /* Free this chain buffer and reset * tracker */ hd->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN; chain = (MPT_FRAME_HDR *) (hd->ChainBuffe
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -