📄 mptscsih.c
字号:
info.buffer = pbuf; info.length = len; info.offset = offset; info.pos = 0; copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name); copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word); copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts); copy_info(&info, "MaxQ=%d\n", ioc->req_depth); return ((info.pos > info.offset) ? info.pos - info.offset : 0);}#ifndef MPTSCSIH_DBG_TIMEOUTstatic int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len){ /* Not yet implemented */ return len;}#else#define is_digit(c) ((c) >= '0' && (c) <= '9')#define digit_to_bin(c) ((c) - '0')#define is_space(c) ((c) == ' ' || (c) == '\t')#define UC_DBG_TIMEOUT 0x01#define UC_DBG_HARDRESET 0x02static int skip_spaces(char *ptr, int len){ int cnt, c; for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --); return (len - cnt);}static int get_int_arg(char *ptr, int len, ulong *pv){ int cnt, c; ulong v; for (v = 0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) { v = (v * 10) + digit_to_bin(c); } if (pv) *pv = v; return (len - cnt);}static int is_keyword(char *ptr, int len, char *verb){ int verb_len = strlen(verb); if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) return verb_len; else return 0;}#define SKIP_SPACES(min_spaces) \ if ((arg_len = skip_spaces(ptr,len)) < (min_spaces)) \ return -EINVAL; \ ptr += arg_len; \ len -= arg_len;#define GET_INT_ARG(v) \ if (!(arg_len = get_int_arg(ptr,len, &(v)))) \ return -EINVAL; \ ptr += arg_len; \ len -= arg_len;static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length){ char *ptr = buffer; char btmp[24]; /* REMOVE */ int arg_len; int len = length; int cmd; ulong number = 1; ulong delta = 10; if ((len > 0) && (ptr[len -1] == '\n')) --len; if (len < 22) { strncpy(btmp, buffer, len); btmp[len+1]='\0'; } else { strncpy(btmp, buffer, 22); btmp[23]='\0'; } printk("user_command: ioc %d, buffer %s, length %d\n", ioc->id, btmp, length); if ((arg_len = is_keyword(ptr, len, "timeout")) != 0) cmd = UC_DBG_TIMEOUT; else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0) cmd = UC_DBG_HARDRESET; else return -EINVAL; ptr += arg_len; len -= arg_len; switch(cmd) { case UC_DBG_TIMEOUT: SKIP_SPACES(1); GET_INT_ARG(number); SKIP_SPACES(1); GET_INT_ARG(delta); break; } printk("user_command: cnt=%ld delta=%ld\n", number, delta); if (len) return -EINVAL; else { if (cmd == UC_DBG_HARDRESET) { ioc->timeout_hard = 1; } else if (cmd == UC_DBG_TIMEOUT) { /* process this command ... */ ioc->timeout_maxcnt = 0; ioc->timeout_delta = delta < 2 ? 2 : delta; ioc->timeout_cnt = 0; ioc->timeout_maxcnt = number < 8 ? number: 8; } } /* Not yet implemented */ return length;}#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_proc_info - Return information about MPT adapter * * (linux scsi_host_template.info routine) * * buffer: if write, user data; if read, buffer for user * length: if write, return length; * offset: if write, 0; if read, the current offset into the buffer from * the previous read. * hostno: scsi host number * func: if write = 1; if read = 0 */int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func){ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; MPT_ADAPTER *ioc = hd->ioc; int size = 0; if (func) { size = mptscsih_user_command(ioc, buffer, length); } else { if (start) *start = buffer; size = mptscsih_host_info(ioc, buffer, offset, length); } return size;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#define ADD_INDEX_LOG(req_ent) do { } while(0)/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. * @SCpnt: Pointer to scsi_cmnd structure * @done: Pointer SCSI mid-layer IO completion function * * (linux scsi_host_template.queuecommand routine) * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest * from a linux scsi_cmnd request and send it to the IOC. * * Returns 0. (rtn value discarded by linux scsi mid-layer) */intmptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){ MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; VirtDevice *pTarget; MPT_DONE_Q *buffer; unsigned long flags; int target; int lun; u32 datalen; u32 scsictl; u32 scsidir; u32 cmd_len; int my_idx; int ii; int rc; int did_errcode; int issueCmd; did_errcode = 0; hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; target = SCpnt->device->id; lun = SCpnt->device->lun; SCpnt->scsi_done = done; pTarget = hd->Targets[target]; dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n", (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); if (hd->resetPending) { /* Prevent new commands from being issued * while reloading the FW. Reset timer to 60 seconds, * as the FW can take some time to come ready. * For New EH, cmds on doneQ posted to FW. */ did_errcode = 1; mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60)); dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); goto did_error; } /* * Put together a MPT SCSI request... */ if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc)) == NULL) { dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", hd->ioc->name)); did_errcode = 2; goto did_error; } pScsiReq = (SCSIIORequest_t *) mf; my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); ADD_INDEX_LOG(my_idx); /* BUG FIX! 19991030 -sralston * TUR's being issued with scsictl=0x02000000 (DATA_IN)! * Seems we may receive a buffer (datalen>0) even when there * will be no data transfer! GRRRRR... */ if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { datalen = SCpnt->request_bufflen; scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { datalen = SCpnt->request_bufflen; scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */ } else { datalen = 0; scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; } /* Default to untagged. Once a target structure has been allocated, * use the Inquiry data to determine if device supports tagged. */ if ( pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; } else { scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED; } /* Use the above information to set up the message frame */ pScsiReq->TargetID = (u8) target; pScsiReq->Bus = (u8) SCpnt->device->channel; pScsiReq->ChainOffset = 0; pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; pScsiReq->CDBLength = SCpnt->cmd_len; pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; pScsiReq->Reserved = 0; pScsiReq->MsgFlags = mpt_msg_flags(); pScsiReq->LUN[0] = 0; pScsiReq->LUN[1] = lun; pScsiReq->LUN[2] = 0; pScsiReq->LUN[3] = 0; pScsiReq->LUN[4] = 0; pScsiReq->LUN[5] = 0; pScsiReq->LUN[6] = 0; pScsiReq->LUN[7] = 0; pScsiReq->Control = cpu_to_le32(scsictl); /* * Write SCSI CDB into the message */ cmd_len = SCpnt->cmd_len; for (ii=0; ii < cmd_len; ii++) pScsiReq->CDB[ii] = SCpnt->cmnd[ii]; for (ii=cmd_len; ii < 16; ii++) pScsiReq->CDB[ii] = 0; /* DataLength */ pScsiReq->DataLength = cpu_to_le32(datalen); /* SenseBuffer low address */ pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma + (my_idx * MPT_SENSE_BUFFER_ALLOC)); /* Now add the SG list * Always have a SGE even if null length. */ rc = SUCCESS; if (datalen == 0) { /* Add a NULL SGE */ mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx); } if (rc == SUCCESS) { hd->ScsiLookup[my_idx] = SCpnt; SCpnt->host_scribble = NULL; /* SCSI specific processing */ issueCmd = 1; if (hd->is_spi) { int dvStatus = hd->ioc->spi_data.dvStatus[target]; if (dvStatus || hd->ioc->spi_data.forceDv) {#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION if ((dvStatus & MPT_SCSICFG_NEED_DV) || (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) { unsigned long lflags; /* Schedule DV if necessary */ spin_lock_irqsave(&dvtaskQ_lock, lflags); if (!dvtaskQ_active) { dvtaskQ_active = 1; spin_unlock_irqrestore(&dvtaskQ_lock, lflags); INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); schedule_work(&mptscsih_dvTask); } else { spin_unlock_irqrestore(&dvtaskQ_lock, lflags); } hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV; } /* 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; } /* Set the DV flags. */ if (dvStatus & MPT_SCSICFG_DV_NOT_DONE) mptscsih_set_dvflags(hd, pScsiReq);#endif } }#ifdef MPTSCSIH_DBG_TIMEOUT if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) { foo_to[hd->ioc->timeout_cnt] = SCpnt; hd->ioc->timeout_cnt++; //mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta); issueCmd = 0; printk(MYIOC_s_WARN_FMT "to pendingQ: (sc=%p, mf=%p, time=%ld)\n", hd->ioc->name, SCpnt, mf, jiffies); }#endif if (issueCmd) { mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", hd->ioc->name, SCpnt, mf, my_idx)); } else { ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n", hd->ioc->name, SCpnt, my_idx)); /* 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, 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)) { dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n", (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); 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_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; 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_HD
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -