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

📄 megaraid.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    megaCfg->qCcnt = 0;    megaCfg->flag = flag;    megaCfg->host = host;    megaCfg->base = megaBase;    megaCfg->host->irq = megaIrq;    megaCfg->host->io_port = megaBase;    megaCfg->host->n_io_port = 16;    megaCfg->host->unique_id = (pdev->bus->number << 8) | pdev->devfn;    megaCtlrs[numCtlrs++] = megaCfg;     if (flag != BOARD_QUARTZ) {      /* Request our IO Range */      if (request_region (megaBase, 16, "megaraid")) {	printk (KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);	scsi_unregister (host);	continue;      }    }    /* Request our IRQ */    if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ,		     "megaraid", megaCfg)) {      printk (KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR,	      megaIrq);      scsi_unregister (host);      continue;    }    mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64));    mega_i_query_adapter (megaCfg);       if (flag == BOARD_QUARTZ) {      /* Check to see if this is a Dell PERC RAID controller model 466 */      u16 subsysid, subsysvid;#if LINUX_VERSION_CODE < 0x20100      pcibios_read_config_word (pciBus, pciDevFun,				PCI_SUBSYSTEM_VENDOR_ID,				&subsysvid);      pcibios_read_config_word (pciBus, pciDevFun,				PCI_SUBSYSTEM_ID,				&subsysid);#else      pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);      pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid);#endif      if ( (subsysid == 0x1111) && (subsysvid == 0x1111) &&           (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) {	printk(KERN_WARNING"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n""megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n""megaraid: with those firmware versions on this specific card.  In order\n""megaraid: to protect your data, please upgrade your firmware to version\n""megaraid: 3.10 or later, available from the Dell Technical Support web\n""megaraid: site at\n""http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");	megaraid_release (host);#ifdef MODULE		continue;#else	while(1) schedule_timeout(1 * HZ);#endif	      }    }    /* Initialize SCBs */    if (mega_initSCB (megaCfg)) {      megaraid_release (host);      continue;    }    numFound++;  }  return numFound;}/*--------------------------------------------------------- * Detects if a megaraid controller exists in this system *---------------------------------------------------------*/int megaraid_detect (Scsi_Host_Template * pHostTmpl){  int count = 0;#ifdef MODULE  if (megaraid)      megaraid_setup(megaraid);#endif  pHostTmpl->proc_name = "megaraid";  printk ("megaraid: " MEGARAID_VERSION CRLFSTR);  count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0);  count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0);  count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);  return count;}/*--------------------------------------------------------------------- * Release the controller's resources *---------------------------------------------------------------------*/int megaraid_release (struct Scsi_Host *pSHost){  mega_host_config *megaCfg;  mega_mailbox *mbox;  u_char mboxData[16];  megaCfg = (mega_host_config *) pSHost->hostdata;  mbox = (mega_mailbox *) mboxData;  /* Flush cache to disk */  memset (mbox, 0, 16);  mboxData[0] = 0xA;  free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise					   extra interrupt is generated */  /* Issue a blocking (interrupts disabled) command to the card */  megaIssueCmd (megaCfg, mboxData, NULL, 0);  /* Free our resources */  if (megaCfg->flag & BOARD_QUARTZ) {    iounmap ((void *) megaCfg->base);  }  else {    release_region (megaCfg->host->io_port, 16);  }  mega_freeSgList(megaCfg);  scsi_unregister (pSHost);  return 0;}static inline void mega_freeSgList(mega_host_config *megaCfg){  int i;  for (i = 0; i < megaCfg->max_cmds; i++) {    if (megaCfg->scbList[i].sgList)      kfree (megaCfg->scbList[i].sgList);	/* free sgList */  }}/*---------------------------------------------- * Get information about the card/driver  *----------------------------------------------*/const char * megaraid_info (struct Scsi_Host *pSHost){  static char buffer[512];  mega_host_config *megaCfg;  megaCfg = (mega_host_config *) pSHost->hostdata;  sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans %d luns",	   megaCfg->fwVer,           megaCfg->productInfo.MaxConcCmds,	   megaCfg->host->max_id,	   megaCfg->host->max_channel,           megaCfg->host->max_lun);  return buffer;}/*----------------------------------------------------------------- * Perform a SCSI command * Mailbox area: *   00 01 command *   01 01 command id *   02 02 # of sectors *   04 04 logical bus address *   08 04 physical buffer address *   0C 01 logical drive # *   0D 01 length of scatter/gather list *   0E 01 reserved *   0F 01 mailbox busy *   10 01 numstatus byte *   11 01 status byte  *-----------------------------------------------------------------*/int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)){  DRIVER_LOCK_T  mega_host_config *megaCfg;  mega_scb *pScb;  megaCfg = (mega_host_config *) SCpnt->host->hostdata;  DRIVER_LOCK(megaCfg);  if (!(megaCfg->flag & (1L << SCpnt->channel))) {    if (SCpnt->channel < SCpnt->host->max_channel)       printk (/*KERN_INFO*/ "scsi%d: scanning channel %c for devices.\n",	    megaCfg->host->host_no,	    SCpnt->channel + '1');    else       printk(/*KERN_INFO*/ "scsi%d: scanning virtual channel for logical drives.\n", megaCfg->host->host_no);           megaCfg->flag |= (1L << SCpnt->channel);  }  SCpnt->scsi_done = pktComp;  /* If driver in abort or reset.. cancel this command */  if (megaCfg->flag & IN_ABORT) {    SCpnt->result = (DID_ABORT << 16);    /* 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++;    DRIVER_UNLOCK(megaCfg);    return 0;  }  else if (megaCfg->flag & IN_RESET) {    SCpnt->result = (DID_RESET << 16);    /* 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++;    DRIVER_UNLOCK(megaCfg);    return 0;  }  megaCfg->flag |= IN_QUEUE;  /* Allocate and build a SCB request */  if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {              /*build SCpnt for IOCTL_CMD_NEW cmd in mega_ioctl()*/    /* Add SCB to the head of the pending queue */    /* Add SCB to the head of the pending queue */    if( megaCfg->qPendingH == NULL ) {      megaCfg->qPendingH = megaCfg->qPendingT = pScb;    }    else {      megaCfg->qPendingT->next = pScb;      megaCfg->qPendingT = pScb;    }    megaCfg->qPendingT->next = NULL;    megaCfg->qPcnt++;      mega_runpendq(megaCfg);#if LINUX_VERSION_CODE > 0x020024    if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )    {  /* user data from external user buffer */          char *user_area;          u32  xfer_size;          init_MUTEX_LOCKED(&pScb->sem);          down(&pScb->sem);          user_area = *((char **)&pScb->SCpnt->cmnd[4]);          xfer_size = *((u32 *)&pScb->SCpnt->cmnd[8]);          copy_to_user(user_area,pScb->kern_area,xfer_size);          kfree(pScb->kern_area);          mega_freeSCB(megaCfg, pScb);    }#endif  }  megaCfg->flag &= ~IN_QUEUE;  DRIVER_UNLOCK(megaCfg);  return 0;}/*---------------------------------------------------------------------- * Issue a blocking command to the controller *----------------------------------------------------------------------*/volatile static int internal_done_flag = 0;volatile static int internal_done_errcode = 0;static DECLARE_WAIT_QUEUE_HEAD(internal_wait);static void internal_done (Scsi_Cmnd * SCpnt){  internal_done_errcode = SCpnt->result;  internal_done_flag++;  wake_up(&internal_wait);}/* shouldn't be used, but included for completeness */int megaraid_command (Scsi_Cmnd * SCpnt){  internal_done_flag = 0;  /* Queue command, and wait until it has completed */  megaraid_queue (SCpnt, internal_done);  while (!internal_done_flag) {	interruptible_sleep_on(&internal_wait);  }  return internal_done_errcode;}/*--------------------------------------------------------------------- * Abort a previous SCSI request *---------------------------------------------------------------------*/intmegaraid_abort (Scsi_Cmnd * SCpnt){  mega_host_config *megaCfg;  int   rc; //, idx;  mega_scb *pScb;  rc = SCSI_ABORT_NOT_RUNNING;  megaCfg = (mega_host_config *) SCpnt->host->hostdata;  megaCfg->flag |= IN_ABORT;  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {    if (pScb->SCpnt == SCpnt) {      /* Found an aborting command */#if DEBUG      showMbox(pScb);#endif/* * If the command is queued to be issued to the firmware, abort the scsi cmd, * If the command is already aborted in a previous call to the _abort entry *  point, return SCSI_ABORT_SNOOZE, suggesting a reset. * If the command is issued to the firmware, which might complete after *  some time, we will mark the scb as aborted, and return to the mid layer,  *  that abort could not be done. *  In the ISR, when this command actually completes, we will perform a normal *  completion. * * Oct 27, 1999 */      switch(pScb->state) {      case SCB_ABORTED: /* Already aborted */	rc = SCSI_ABORT_SNOOZE;	break;      case SCB_ISSUED: /* Waiting on ISR result */	rc = SCSI_ABORT_NOT_RUNNING;	pScb->state = SCB_ABORTED;	break;      case SCB_ACTIVE: /* still on the pending queue */	mega_freeSCB (megaCfg, pScb);	SCpnt->result = (DID_ABORT << 16) ;        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++;	rc = SCSI_ABORT_SUCCESS;        break;      default:        printk("megaraid_abort: unknown command state!!\n");        rc = SCSI_ABORT_NOT_RUNNING;	break;      }      break;    }  }  megaCfg->flag &= ~IN_ABORT;#if DEBUGif(megaCfg->flag & IN_QUEUE)  printk("ma:flag is in queue\n");if(megaCfg->qCompletedH == NULL) printk("ma:qchead == null\n");#endif  /* * This is required here to complete any completed requests to be communicated * over to the mid layer. * Calling just mega_rundoneq() did not work. */if(megaCfg->qCompletedH) {  SCpnt = megaCfg->qCompletedH;  megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;  megaCfg->qCcnt--;  SCpnt->host_scribble = (unsigned char *) NULL ;  /* Callback */  callDone (SCpnt);}  mega_rundoneq(megaCfg);  return rc;}/*--------------------------------------------------------------------- * Reset a previous SCSI request *---------------------------------------------------------------------*/int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags){  mega_host_config *megaCfg;  int idx;  int rc;  mega_scb *pScb;  rc = SCSI_RESET_NOT_RUNNING;  megaCfg = (mega_host_config *) SCpnt->host->hostdata;  megaCfg->flag |= IN_RESET;  printk ("megaraid_RESET: %.08lx cmd=%.02x <c=%d.t=%d.l=%d>, flag = %x\n",	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,	  SCpnt->lun, rstflags);  TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,	  SCpnt->lun));  /*   * Walk list of SCBs for any that are still outstanding   */  for (idx = 0; idx < megaCfg->max_cmds; idx++) {    if (megaCfg->scbList[idx].state != SCB_FREE) {      SCpnt = megaCfg->scbList[idx].SCpnt;      pScb = &megaCfg->scbList[idx];      if (SCpnt != NULL) {        pScb->state = SCB_RESET;        break;      }    }  }  megaCfg->flag &= ~IN_RESET;  mega_rundoneq(megaCfg);  return rc;}/*------------------------------------------------------------- * Return the disk geometry for a particular disk * Input: *   Disk *disk - Disk geometry *   kdev_t dev - Device node *   int *geom  - Returns geometry fields *     geom[0] = heads *     geom[1] = sectors *     geom[2] = cylinders *-------------------------------------------------------------*/int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom){  int heads, sectors, cylinders;  mega_host_config *megaCfg;  /* Get pointer to host config structure */  megaCfg = (mega_host_config *) disk->device->host->hostdata;  /* Default heads (64) & sectors (32) */  heads = 64;  sectors = 32;  cylinders = disk->capacity / (heads * sectors);  /* Handle extended translation size for logical drives > 1Gb */  if (disk->capacity >= 0x200000) {    heads = 255;    sectors = 63;    cylinders = disk->capacity / (heads * sectors);  }  /* return result */  geom[0] = heads;  geom[1] = sectors;  geom[2] = cylinders;  return 0;}static int __init megaraid_setup(char *str){  skip_id = -1;  if (str && !strncmp(str, "skip", strlen("skip"))) {      if (str[4] != '\0') {          skip_id = str[4] - '0';          if (str[5] != '\0') {              skip_id = (skip_id * 10) + (str[5] - '0');          }      }      skip_id = (skip_id > 15) ? -1 : skip_id;  }  return 1;}__setup("megaraid=", megaraid_setup);static Scsi_Host_Template driver_template = MEGARAID;#include "scsi_module.c"

⌨️ 快捷键说明

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