📄 megaraid.c
字号:
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 + -