⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 megaraid.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
  /* Issue any pending commands to the card */  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {    if (pScb->state == SCB_ACTIVE) {      if(megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1))	return;    }  }}/* Add command to the list of completed requests */static voidmega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 			   int status){  int islogical;  Scsi_Cmnd *SCpnt;  mega_passthru *pthru;  mega_mailbox *mbox;  if (pScb == NULL) {	TRACE(("NULL pScb in mega_cmd_done!"));	printk("NULL pScb in mega_cmd_done!");  }  SCpnt = pScb->SCpnt;  pthru = &pScb->pthru;  mbox = (mega_mailbox *) &pScb->mboxData;  if (SCpnt == NULL) {	TRACE(("NULL SCpnt in mega_cmd_done!"));	TRACE(("pScb->idx = ",pScb->idx));	TRACE(("pScb->state = ",pScb->state));	TRACE(("pScb->state = ",pScb->state));	printk("megaraid:Problem...!\n");	while(1);  }  islogical = (SCpnt->channel == megaCfg->host->max_channel);  if (SCpnt->cmnd[0] == INQUIRY &&      ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&      !islogical) {    status = 0xF0;  }/* clear result; otherwise, success returns corrupt value */  SCpnt->result = 0;  if ((SCpnt->cmnd[0] & 0x80) ) {/* i.e. ioctl cmd such as 0x80, 0x81 of megamgr*/    switch (status) {      case 0xF0:      case 0xF4:	SCpnt->result=(DID_BAD_TARGET<<16)|status;        break;      default:	SCpnt->result|=status;   }/*end of switch*/}else{  /* Convert MegaRAID status to Linux error code */  switch (status) {  case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD*/    SCpnt->result |= (DID_OK << 16);    break;  case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */	/*set sense_buffer and result fields*/       if( mbox->cmd==MEGA_MBOXCMD_PASSTHRU ){	  memcpy( SCpnt->sense_buffer , pthru->reqsensearea, 14);          SCpnt->result = (DRIVER_SENSE<<24)|(DID_ERROR << 16)|status;        }       else{ 	  SCpnt->sense_buffer[0]=0x70;	  SCpnt->sense_buffer[2]=ABORTED_COMMAND;          SCpnt->result |= (CHECK_CONDITION << 1);       }    break;  case 0x08:  /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */    SCpnt->result |= (DID_BUS_BUSY << 16)|status;    break;  default:     SCpnt->result |= (DID_BAD_TARGET << 16)|status;    break;  } }  if ( SCpnt->cmnd[0]!=IOCTL_CMD_NEW )   /* not IOCTL_CMD_NEW SCB, freeSCB()*/  /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()   * after copy data back to user space*/     mega_freeSCB(megaCfg, pScb);  /* Add Scsi_Command to end of completed queue */    if( megaCfg->qCompletedH == NULL ) {      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;    }    else {      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;      megaCfg->qCompletedT = SCpnt;   }   megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;   megaCfg->qCcnt++;}/*------------------------------------------------------------------- * *                 Build a SCB from a Scsi_Cmnd * * Returns a SCB pointer, or NULL * If NULL is returned, the scsi_done function MUST have been called * *-------------------------------------------------------------------*/static mega_scb * mega_build_cmd (mega_host_config * megaCfg, 				  Scsi_Cmnd * SCpnt){  mega_scb *pScb;  mega_mailbox *mbox;  mega_passthru *pthru;  long seg;  char islogical;  char lun = SCpnt->lun;  if ((SCpnt->cmnd[0] == 0x80)  || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) )  /* ioctl */    return mega_ioctl (megaCfg, SCpnt);   islogical = (SCpnt->channel == megaCfg->host->max_channel);  if (!islogical && lun != 0) {    SCpnt->result = (DID_BAD_TARGET << 16);    callDone (SCpnt);    return NULL;  }  if (!islogical && SCpnt->target == skip_id) {	SCpnt->result = (DID_BAD_TARGET << 16);	callDone (SCpnt);	return NULL;  }  if ( islogical ) {	lun = (SCpnt->target * 8) + lun;        if ( lun > FC_MAX_LOGICAL_DRIVES ){            SCpnt->result = (DID_BAD_TARGET << 16);            callDone (SCpnt);            return NULL;        }  }  /*-----------------------------------------------------   *   *               Logical drive commands   *   *-----------------------------------------------------*/  if (islogical) {    switch (SCpnt->cmnd[0]) {    case TEST_UNIT_READY:      memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen);      SCpnt->result = (DID_OK << 16);      callDone (SCpnt);      return NULL;    case MODE_SENSE:      memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]);      SCpnt->result = (DID_OK << 16);      callDone (SCpnt);      return NULL;    case READ_CAPACITY:    case INQUIRY:      /* Allocate a SCB and initialize passthru */      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {	SCpnt->result = (DID_ERROR << 16);	callDone (SCpnt);	return NULL;      }      pthru = &pScb->pthru;      mbox = (mega_mailbox *) & pScb->mboxData;      memset (mbox, 0, sizeof (pScb->mboxData));      memset (pthru, 0, sizeof (mega_passthru));      pthru->timeout = 0;      pthru->ars = 1;      pthru->reqsenselen = 14;      pthru->islogical = 1;      pthru->logdrv = lun;      pthru->cdblen = SCpnt->cmd_len;      pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer);      pthru->dataxferlen = SCpnt->request_bufflen;      memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);      /* Initialize mailbox area */      mbox->cmd = MEGA_MBOXCMD_PASSTHRU;      mbox->xferaddr = virt_to_bus (pthru);      return pScb;    case READ_6:    case WRITE_6:    case READ_10:    case WRITE_10:      /* Allocate a SCB and initialize mailbox */      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {	SCpnt->result = (DID_ERROR << 16);	callDone (SCpnt);	return NULL;      }      mbox = (mega_mailbox *) & pScb->mboxData;      memset (mbox, 0, sizeof (pScb->mboxData));      mbox->logdrv = lun;      mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ?	MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE;      /* 6-byte */      if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {	mbox->numsectors =	  (u32) SCpnt->cmnd[4];	mbox->lba =	  ((u32) SCpnt->cmnd[1] << 16) |	  ((u32) SCpnt->cmnd[2] << 8) |	  (u32) SCpnt->cmnd[3];	mbox->lba &= 0x1FFFFF;      }      /* 10-byte */      if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {	mbox->numsectors =	  (u32) SCpnt->cmnd[8] |	  ((u32) SCpnt->cmnd[7] << 8);	mbox->lba =	  ((u32) SCpnt->cmnd[2] << 24) |	  ((u32) SCpnt->cmnd[3] << 16) |	  ((u32) SCpnt->cmnd[4] << 8) |	  (u32) SCpnt->cmnd[5];      }      /* Calculate Scatter-Gather info */      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,					  (u32 *) & mbox->xferaddr,					  (u32 *) & seg);      return pScb;    default:      SCpnt->result = (DID_BAD_TARGET << 16);      callDone (SCpnt);      return NULL;    }  }  /*-----------------------------------------------------   *   *               Passthru drive commands   *   *-----------------------------------------------------*/  else {    /* Allocate a SCB and initialize passthru */    if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {      SCpnt->result = (DID_ERROR << 16);      callDone (SCpnt);      return NULL;    }    pthru = &pScb->pthru;    mbox = (mega_mailbox *) pScb->mboxData;    memset (mbox, 0, sizeof (pScb->mboxData));    memset (pthru, 0, sizeof (mega_passthru));    pthru->timeout = 2; /*set adapter timeout value to 10 min. for tape drive*/     		        /* 0=6sec/1=60sec/2=10min/3=3hrs */    pthru->ars = 1;    pthru->reqsenselen = 14;    pthru->islogical = 0;    pthru->channel = (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;    pthru->target = (megaCfg->flag & BOARD_40LD) ? /*BOARD_40LD*/                     (SCpnt->channel<<4)|SCpnt->target : SCpnt->target;    pthru->cdblen = SCpnt->cmd_len;    memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,					 (u32 *) & pthru->dataxferaddr,					 (u32 *) & pthru->dataxferlen);    /* Initialize mailbox */    mbox->cmd = MEGA_MBOXCMD_PASSTHRU;    mbox->xferaddr = virt_to_bus (pthru);    return pScb;  }  return NULL;}/*-------------------------------------------------------------------- * build RAID commands for controller, passed down through ioctl() *--------------------------------------------------------------------*/static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt){  mega_scb *pScb;  mega_ioctl_mbox *mbox;  mega_mailbox *mailbox;  mega_passthru *pthru;  u8 *mboxdata;  long seg;  unsigned char *data = (unsigned char *)SCpnt->request_buffer;  int i;  if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {    SCpnt->result = (DID_ERROR << 16);    callDone (SCpnt);    return NULL;  }  mboxdata = (u8 *) & pScb->mboxData;  mbox = (mega_ioctl_mbox *) & pScb->mboxData;  mailbox = (mega_mailbox *) & pScb->mboxData;  memset (mailbox, 0, sizeof (pScb->mboxData));  if (data[0] == 0x03) {	/* passthrough command */    unsigned char cdblen = data[2];    pthru = &pScb->pthru;    memset (pthru, 0, sizeof (mega_passthru));    pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0;    pthru->timeout = data[cdblen+3] & 0x07;    pthru->reqsenselen = 14;    pthru->ars = (data[cdblen+3] & 0x08) ? 1:0;    pthru->logdrv = data[cdblen+4];    pthru->channel = data[cdblen+5];    pthru->target = data[cdblen+6];    pthru->cdblen = cdblen;    memcpy (pthru->cdb, &data[3], cdblen);    mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;    mailbox->xferaddr = virt_to_bus (pthru);    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,					 (u32 *) & pthru->dataxferaddr,					 (u32 *) & pthru->dataxferlen);    for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) {       data[i] = data[i+cdblen+7];    }    return pScb;  }  /* else normal (nonpassthru) command */#if LINUX_VERSION_CODE > 0x020024/* * usage of the function copy from user is used in case of data more than * 4KB.  This is used only with adapters which supports more than 8 logical * drives.  This feature is disabled on kernels earlier or same as 2.0.36 * as the uaccess.h file is not available with those kernels. */  if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) {             /* use external data area for large xfers  */     /* If cmnd[0] is set to IOCTL_CMD_NEW then *      *   cmnd[4..7] = external user buffer     *      *   cmnd[8..11] = length of buffer        *      *                                         */      char *kern_area;      char *user_area = *((char **)&SCpnt->cmnd[4]);      u32 xfer_size = *((u32 *)&SCpnt->cmnd[8]);      if (verify_area(VERIFY_READ, user_area, xfer_size)) {          printk("megaraid: Got bad user address.\n");          SCpnt->result = (DID_ERROR << 16);          callDone (SCpnt);          return NULL;      }      kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA);      if (kern_area == NULL) {          printk("megaraid: Couldn't allocate kernel mem.\n");	  SCpnt->result = (DID_ERROR << 16);	  callDone (SCpnt);	  return NULL;      }      copy_from_user(kern_area,user_area,xfer_size);      pScb->kern_area = kern_area;  }#endif  mbox->cmd = data[0];  mbox->channel = data[1];  mbox->param = data[2];  mbox->pad[0] = data[3];  mbox->logdrv = data[4];  if(SCpnt->cmnd[0] == IOCTL_CMD_NEW) {      if(data[0]==DCMD_FC_CMD){ /*i.e. 0xA1, then override some mbox data */          *(mboxdata+0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD*/          *(mboxdata+2) = data[2]; /*sub command*/          *(mboxdata+3) = 0;       /*number of elements in SG list*/          mbox->xferaddr           /*i.e. mboxdata byte 0x8 to 0xb*/                        = virt_to_bus(pScb->kern_area);      }      else{         mbox->xferaddr = virt_to_bus(pScb->kern_area);         mbox->numsgelements = 0;      }  }   else {      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,				      (u32 *) & mbox->xferaddr,				      (u32 *) & seg);      for (i=0;i<(SCpnt->request_bufflen-6);i++) {          data[i] = data[i+6];      }  }  return (pScb);}#if DEBUGstatic void showMbox(mega_scb *pScb){  mega_mailbox *mbox;  if (pScb == NULL) return;  mbox = (mega_mailbox *)pScb->mboxData;  printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n",	 pScb->SCpnt->pid, 	 mbox->cmd, mbox->cmdid, mbox->numsectors,	 mbox->lba, mbox->xferaddr, mbox->logdrv,	 mbox->numsgelements);}#endif#if DEBUGstatic unsigned int cum_time = 0;static unsigned int cum_time_cnt = 0;#endif/*-------------------------------------------------------------------- * Interrupt service routine *--------------------------------------------------------------------*/static void megaraid_isr (int irq, void *devp, struct pt_regs *regs){#if LINUX_VERSION_CODE >= 0x20100  IO_LOCK_T#endif  mega_host_config    *megaCfg;  u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];  u32 dword=0;  mega_mailbox *mbox;  mega_scb *pScb;  u_char qCnt, qStatus;  u_char            completed[MAX_FIRMWARE_STATUS];  Scsi_Cmnd *SCpnt;  megaCfg = (mega_host_config *) devp;  mbox = (mega_mailbox *)tmpBox;  if (megaCfg->host->irq == irq) {    if (megaCfg->flag & IN_ISR) {      printk(KERN_ERR "ISR called reentrantly!!\n");    }    megaCfg->flag |= IN_ISR;    if (mega_busyWaitMbox(megaCfg)) {	printk(KERN_WARNING "Error: mailbox busy in isr!\n");    }    /* Check if a valid interrupt is pending */    if (megaCfg->flag & BOARD_QUARTZ) {      dword = RDOUTDOOR (megaCfg);      if (dword != 0x10001234) {	/* Spurious interrupt */	megaCfg->flag &= ~IN_ISR;	return;      }    }    else {      byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);      if ((byte & VALID_INTR_BYTE) == 0) {	/* Spurious interrupt */	megaCfg->flag &= ~IN_ISR;	return;      }      WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);    }    for(idx=0;idx<MAX_FIRMWARE_STATUS;idx++ ) completed[idx] = 0;    IO_LOCK;    qCnt = 0xff;    while ((qCnt = megaCfg->mbox->numstatus) == 0xFF)       ;    qStatus = 0xff;    while ((qStatus = megaCfg->mbox->status) == 0xFF)      ;    /* Get list of completed requests */    for (idx = 0; idx<qCnt; idx++) {      while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) {	printk("p");      }      completed[idx] = sIdx;      sIdx = 0xFF;    }    if (megaCfg->flag & BOARD_QUARTZ) {      WROUTDOOR (megaCfg, dword);      /* Acknowledge interrupt */      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -