megaraid.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:136k
- memset (mbox, 0, 16);
- /*
- * Try to issue Enquiry3 command
- * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
- * update enquiry3 structure
- */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- enquiry3_dma_handle = pci_map_single (megaCfg->dev,
- (void *) megaCfg->mega_buffer,
- (2 * 1024L), PCI_DMA_FROMDEVICE);
- mbox->xferaddr = enquiry3_dma_handle;
- #else
- /*Taken care */
- mbox->xferaddr = virt_to_bus ((void *) megaCfg->mega_buffer);
- #endif
- /* Initialize mailbox databuffer addr */
- enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer;
- /* point mega_Enguiry3 to the data buf */
- mboxData[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */
- mboxData[2] = NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */
- mboxData[3] = ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */
- /* Issue a blocking command to the card */
- if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0) { /* the adapter does not support 40ld */
- mega_RAIDINQ adapterInquiryData;
- mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- raid_inq_dma_handle = pci_map_single (megaCfg->dev,
- (void *) adapterInquiryPnt,
- sizeof (mega_RAIDINQ),
- PCI_DMA_FROMDEVICE);
- mbox->xferaddr = raid_inq_dma_handle;
- #else
- /*taken care */
- mbox->xferaddr = virt_to_bus ((void *) adapterInquiryPnt);
- #endif
- mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; /*issue old 0x05 command to adapter */
- /* Issue a blocking command to the card */ ;
- retval = megaIssueCmd (megaCfg, mboxData, NULL, 0);
- pci_unmap_single (megaCfg->dev,
- raid_inq_dma_handle,
- sizeof (mega_RAIDINQ), PCI_DMA_FROMDEVICE);
- /*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/
- mega_Convert8ldTo40ld (adapterInquiryPnt,
- enquiry3Pnt,
- (megaRaidProductInfo *) & megaCfg->
- productInfo);
- } else { /* adapter supports 40ld */
- megaCfg->flag |= BOARD_40LD;
- pci_unmap_single (megaCfg->dev,
- enquiry3_dma_handle,
- (2 * 1024L), PCI_DMA_FROMDEVICE);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /*get productInfo, which is static information and will be unchanged*/
- prod_info_dma_handle
- = pci_map_single (megaCfg->dev,
- (void *) &megaCfg->productInfo,
- sizeof (megaRaidProductInfo),
- PCI_DMA_FROMDEVICE);
- mbox->xferaddr = prod_info_dma_handle;
- #else
- /*taken care */
- mbox->xferaddr = virt_to_bus ((void *) &megaCfg->productInfo);
- #endif
- mboxData[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */
- mboxData[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */
- if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0)
- printk ("megaraid: Product_info cmd failed with error: %dn",
- retval);
- pci_unmap_single (megaCfg->dev,
- prod_info_dma_handle,
- sizeof (megaRaidProductInfo),
- PCI_DMA_FROMDEVICE);
- }
- /*
- * kernel scans the channels from 0 to <= max_channel
- */
- megaCfg->host->max_channel =
- megaCfg->productInfo.SCSIChanPresent + NVIRT_CHAN -1;
- megaCfg->host->max_id = 16; /* max targets per channel */
- /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1; */
- #if 0
- megaCfg->host->max_lun = /* max lun */
- (megaCfg->flag & BOARD_40LD) ?
- FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
- #endif
- megaCfg->host->max_lun = 7; /* Upto 7 luns for non disk devices */
- megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
- megaCfg->numldrv = enquiry3Pnt->numLDrv;
- megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds;
- if (megaCfg->max_cmds > MAX_COMMANDS)
- megaCfg->max_cmds = MAX_COMMANDS - 1;
- megaCfg->host->can_queue = megaCfg->max_cmds - 1;
- #if 0
- if (megaCfg->host->can_queue >= MAX_COMMANDS) {
- megaCfg->host->can_queue = MAX_COMMANDS - 16;
- }
- #endif
- /* use HP firmware and bios version encoding */
- if (megaCfg->productInfo.subSystemVendorID == HP_SUBSYS_ID) {
- sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
- megaCfg->productInfo.FwVer[2],
- megaCfg->productInfo.FwVer[1] >> 8,
- megaCfg->productInfo.FwVer[1] & 0x0f,
- megaCfg->productInfo.FwVer[0] >> 8,
- megaCfg->productInfo.FwVer[0] & 0x0f);
- sprintf (megaCfg->biosVer, "%c%d%d.%d%d",
- megaCfg->productInfo.BiosVer[2],
- megaCfg->productInfo.BiosVer[1] >> 8,
- megaCfg->productInfo.BiosVer[1] & 0x0f,
- megaCfg->productInfo.BiosVer[0] >> 8,
- megaCfg->productInfo.BiosVer[0] & 0x0f);
- } else {
- memcpy (megaCfg->fwVer, (char *) megaCfg->productInfo.FwVer, 4);
- megaCfg->fwVer[4] = 0;
- memcpy (megaCfg->biosVer, (char *) megaCfg->productInfo.BiosVer, 4);
- megaCfg->biosVer[4] = 0;
- }
- megaCfg->support_ext_cdb = mega_support_ext_cdb(megaCfg);
- printk (KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
- megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv);
- if ( megaCfg->support_ext_cdb ) {
- printk(KERN_NOTICE "megaraid: supports extended CDBs.n");
- }
- /*
- * I hope that I can unmap here, reason DMA transaction is not required any more
- * after this
- */
- return 0;
- }
- /*-------------------------------------------------------------------------
- *
- * Driver interface functions
- *
- *-------------------------------------------------------------------------*/
- /*----------------------------------------------------------
- * Returns data to be displayed in /proc/scsi/megaraid/X
- *----------------------------------------------------------*/
- int megaraid_proc_info (char *buffer, char **start, off_t offset,
- int length, int host_no, int inout)
- {
- *start = buffer;
- return 0;
- }
- static int mega_findCard (Scsi_Host_Template * pHostTmpl,
- u16 pciVendor, u16 pciDev, long flag)
- {
- mega_host_config *megaCfg = NULL;
- struct Scsi_Host *host = NULL;
- u_char pciBus, pciDevFun, megaIrq;
- u16 magic;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- u32 magic64;
- #endif
- int i;
- #if BITS_PER_LONG==64
- u64 megaBase;
- #else
- u32 megaBase;
- #endif
- u16 pciIdx = 0;
- u16 numFound = 0;
- u16 subsysid, subsysvid;
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
- while (!pcibios_find_device
- (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
- #else
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */
- struct pci_dev *pdev = NULL;
- #else
- struct pci_dev *pdev = pci_devices;
- #endif
- while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
- if(pci_enable_device (pdev))
- continue;
- pciBus = pdev->bus->number;
- pciDevFun = pdev->devfn;
- #endif
- if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
- pcibios_read_config_word (pciBus, pciDevFun,
- PCI_CONF_AMISIG, &magic);
- if ((magic != AMI_SIGNATURE)
- && (magic != AMI_SIGNATURE_471)) {
- pciIdx++;
- continue; /* not an AMI board */
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pcibios_read_config_dword (pciBus, pciDevFun,
- PCI_CONF_AMISIG64, &magic64);
- if (magic64 == AMI_64BIT_SIGNATURE)
- flag |= BOARD_64BIT;
- #endif
- }
- /* Hmmm...Should we not make this more modularized so that in future we dont add
- for each firmware */
- if (flag & BOARD_QUARTZ) {
- /* Check to see if this is a Dell PERC RAID controller model 466 */
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 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 0
- /*
- * This routine is called with well know values and we
- * should not be getting what we have not asked.
- * Also, the check is not right. It should have been for
- * pci_vendor_id not subsysvid - AM
- */
- /* If we dont detect this valid subsystem vendor id's
- we refuse to load the driver
- PART of PC200X compliance
- */
- if ((subsysvid != AMI_SUBSYS_ID)
- && (subsysvid != DELL_SUBSYS_ID)
- && (subsysvid != HP_SUBSYS_ID))
- continue;
- #endif
- }
- printk (KERN_NOTICE
- "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %dn",
- pciVendor, pciDev, pciIdx, pciBus, PCI_SLOT (pciDevFun),
- PCI_FUNC (pciDevFun));
- /* Read the base port and IRQ from PCI */
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
- pcibios_read_config_dword (pciBus, pciDevFun,
- PCI_BASE_ADDRESS_0,
- (u_int *) & megaBase);
- pcibios_read_config_byte (pciBus, pciDevFun,
- PCI_INTERRUPT_LINE, &megaIrq);
- #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */
- megaBase = pdev->base_address[0];
- megaIrq = pdev->irq;
- #else
- megaBase = pci_resource_start (pdev, 0);
- megaIrq = pdev->irq;
- #endif
- pciIdx++;
- if (flag & BOARD_QUARTZ) {
- megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
- megaBase = (long) ioremap (megaBase, 128);
- if (!megaBase)
- continue;
- } else {
- megaBase &= PCI_BASE_ADDRESS_IO_MASK;
- megaBase += 0x10;
- }
- /* Initialize SCSI Host structure */
- host = scsi_register (pHostTmpl, sizeof (mega_host_config));
- if (!host)
- goto err_unmap;
- /*
- * Comment the following initialization if you know 'max_sectors' is
- * not defined for this kernel.
- * This field was introduced in Linus's kernel 2.4.7pre3 and it
- * greatly increases the IO performance - AM
- */
- host->max_sectors = 1024;
- scsi_set_pci_device(host, pdev);
- megaCfg = (mega_host_config *) host->hostdata;
- memset (megaCfg, 0, sizeof (mega_host_config));
- printk (KERN_NOTICE "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d"
- M_RD_CRLFSTR, host->host_no, (u_int) megaBase, megaIrq);
- if (flag & BOARD_64BIT)
- printk (KERN_NOTICE "scsi%d : Enabling 64 bit supportn",
- host->host_no);
- /* Copy resource info into structure */
- megaCfg->qCompletedH = NULL;
- megaCfg->qCompletedT = NULL;
- megaCfg->qPendingH = NULL;
- megaCfg->qPendingT = NULL;
- megaCfg->qFreeH = NULL;
- megaCfg->qFreeT = NULL;
- megaCfg->qFcnt = 0;
- megaCfg->qPcnt = 0;
- megaCfg->qCcnt = 0;
- megaCfg->lock_free = SPIN_LOCK_UNLOCKED;
- megaCfg->lock_pend = SPIN_LOCK_UNLOCKED;
- megaCfg->lock_scsicmd = SPIN_LOCK_UNLOCKED;
- megaCfg->flag = flag;
- megaCfg->int_qh = NULL;
- megaCfg->int_qt = NULL;
- megaCfg->int_qlen = 0;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- megaCfg->dev = pdev;
- #endif
- 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 = (pciBus << 8) | pciDevFun;
- 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!n");
- goto err_unregister;
- }
- }
- /* Request our IRQ */
- if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ,
- "megaraid", megaCfg)) {
- printk (KERN_WARNING
- "megaraid: Couldn't register IRQ %d!n",
- megaIrq);
- goto err_release;
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /*
- * unmap while releasing the driver, Is it required to be
- * PCI_DMA_BIDIRECTIONAL
- */
- megaCfg->mailbox64ptr
- = pci_alloc_consistent (megaCfg->dev,
- sizeof (mega_mailbox64),
- &(megaCfg->dma_handle64));
- mega_register_mailbox (megaCfg,
- virt_to_bus ((void *) megaCfg->
- mailbox64ptr));
- #else
- mega_register_mailbox (megaCfg,
- virt_to_bus ((void *) &megaCfg->
- mailbox64));
- #endif
- mega_i_query_adapter (megaCfg);
- if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
- /*
- * Which firmware
- */
- if( strcmp(megaCfg->fwVer, "3.00") == 0 ||
- strcmp(megaCfg->fwVer, "3.01") == 0 ) {
- printk( KERN_WARNING
- "megaraid: Your card is a Dell PERC 2/SC RAID controller "
- "with firmwarenmegaraid: 3.00 or 3.01. This driver is "
- "known to have corruption issuesnmegaraid: with those "
- "firmware versions on this specific card. In ordern"
- "megaraid: to protect your data, please upgrade your "
- "firmware to versionnmegaraid: 3.10 or later, available "
- "from the Dell Technical Support webnmegaraid: site atn"
- "http://support.dell.com/us/en/filelib/download/"
- "index.asp?fileid=2940n"
- );
- }
- }
- /*
- * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with
- * firmware H.01.07 or H.01.08, disable 64 bit support,
- * since this firmware cannot handle 64 bit addressing
- */
- if( (subsysvid == HP_SUBSYS_ID) &&
- ((subsysid == 0x60E7)||(subsysid == 0x60E8)) ) {
- /*
- * which firmware
- */
- if( strcmp(megaCfg->fwVer, "H01.07") == 0 ||
- strcmp(megaCfg->fwVer, "H01.08") == 0 ||
- strcmp(megaCfg->fwVer, "H01.09") == 0 )
- {
- printk(KERN_WARNING
- "megaraid: Firmware H.01.07/8/9 on 1M/2M "
- "controllersnmegaraid: do not support 64 bit "
- "addressing.n"
- "megaraid: DISABLING 64 bit support.n");
- megaCfg->flag &= ~BOARD_64BIT;
- }
- }
- if (mega_is_bios_enabled (megaCfg)) {
- mega_hbas[numCtlrs].is_bios_enabled = 1;
- }
- /*
- * Find out which channel is raid and which is scsi
- */
- mega_enum_raid_scsi(megaCfg);
- for( i = 0; i < megaCfg->productInfo.SCSIChanPresent; i++ ) {
- if(IS_RAID_CH(i))
- printk(KERN_NOTICE"megaraid: channel[%d] is raid.n", i+1);
- else
- printk(KERN_NOTICE"megaraid: channel[%d] is scsi.n", i+1);
- }
- /*
- * Find out if a logical drive is set as the boot drive. If there is
- * one, will make that as the first logical drive.
- */
- mega_get_boot_ldrv(megaCfg);
- mega_hbas[numCtlrs].hostdata_addr = megaCfg;
- /*
- * Do we support random deletion and addition of logical drives
- */
- megaCfg->read_ldidmap = 0; /* set it after first logdrv delete cmd */
- megaCfg->support_random_del = mega_support_random_del(megaCfg);
- /* Initialize SCBs */
- if (mega_init_scb (megaCfg)) {
- pci_free_consistent (megaCfg->dev,
- sizeof (mega_mailbox64),
- (void *) megaCfg->mailbox64ptr,
- megaCfg->dma_handle64);
- scsi_unregister (host);
- continue;
- }
- /*
- * Fill in the structure which needs to be passed back to the
- * application when it does an ioctl() for controller related
- * information.
- */
- i = numCtlrs;
- numCtlrs++;
- mcontroller[i].base = megaBase;
- mcontroller[i].irq = megaIrq;
- mcontroller[i].numldrv = megaCfg->numldrv;
- mcontroller[i].pcibus = pciBus;
- mcontroller[i].pcidev = pciDev;
- mcontroller[i].pcifun = PCI_FUNC (pciDevFun);
- mcontroller[i].pciid = pciIdx;
- mcontroller[i].pcivendor = pciVendor;
- mcontroller[i].pcislot = PCI_SLOT (pciDevFun);
- mcontroller[i].uid = (pciBus << 8) | pciDevFun;
- numFound++;
- /* Set the Mode of addressing to 64 bit */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- if ((megaCfg->flag & BOARD_64BIT) && BITS_PER_LONG == 64)
- #if BITS_PER_LONG==64
- pdev->dma_mask = 0xffffffffffffffff;
- #else
- pdev->dma_mask = 0xffffffff;
- #endif
- #endif
- continue;
- err_release:
- if (flag & BOARD_QUARTZ)
- release_region (megaBase, 16);
- err_unregister:
- scsi_unregister (host);
- err_unmap:
- if (flag & BOARD_QUARTZ)
- iounmap ((void *) megaBase);
- }
- return numFound;
- }
- /*---------------------------------------------------------
- * Detects if a megaraid controller exists in this system
- *---------------------------------------------------------*/
- int megaraid_detect (Scsi_Host_Template * pHostTmpl)
- {
- int ctlridx = 0, count = 0;
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */
- pHostTmpl->proc_dir = &proc_scsi_megaraid;
- #else
- pHostTmpl->proc_name = "megaraid";
- #endif
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
- if (!pcibios_present ()) {
- printk (KERN_WARNING "megaraid: PCI bios not present."
- M_RD_CRLFSTR);
- return 0;
- }
- #endif
- skip_id = -1;
- if (megaraid && !strncmp (megaraid, "skip", strlen ("skip"))) {
- if (megaraid[4] != ' ') {
- skip_id = megaraid[4] - '0';
- if (megaraid[5] != ' ') {
- skip_id = (skip_id * 10) + (megaraid[5] - '0');
- }
- }
- skip_id = (skip_id > 15) ? -1 : skip_id;
- }
- printk (KERN_NOTICE "megaraid: " MEGARAID_VERSION);
- memset (mega_hbas, 0, sizeof (mega_hbas));
- count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
- PCI_DEVICE_ID_AMI_MEGARAID, 0);
- count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
- PCI_DEVICE_ID_AMI_MEGARAID2, 0);
- count += mega_findCard (pHostTmpl, 0x8086,
- PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
- count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
- PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
- mega_reorder_hosts ();
- #ifdef CONFIG_PROC_FS
- if (count) {
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */
- mega_proc_dir_entry = proc_mkdir ("megaraid", &proc_root);
- #else
- mega_proc_dir_entry = create_proc_entry ("megaraid",
- S_IFDIR | S_IRUGO |
- S_IXUGO, &proc_root);
- #endif
- if (!mega_proc_dir_entry)
- printk ("megaraid: failed to create megaraid rootn");
- else
- for (ctlridx = 0; ctlridx < count; ctlridx++)
- mega_create_proc_entry (ctlridx,
- mega_proc_dir_entry);
- }
- #endif
- /*
- * Register the driver as a character device, for applications to access
- * it for ioctls.
- * Ideally, this should go in the init_module() routine, but since it is
- * hidden in the file "scsi_module.c" ( included in the end ), we define
- * it here
- * First argument (major) to register_chrdev implies a dynamic major
- * number allocation.
- */
- if (count) {
- major = register_chrdev (0, "megadev", &megadev_fops);
- /*
- * Register the Shutdown Notification hook in kernel
- */
- if (register_reboot_notifier (&mega_notifier)) {
- printk ("MegaRAID Shutdown routine not registered!!n");
- }
- init_MUTEX (&mimd_entry_mtx);
- }
- 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];
- int i;
- 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);
- pci_free_consistent (megaCfg->dev,
- sizeof (mega_mailbox64),
- (void *) megaCfg->mailbox64ptr,
- megaCfg->dma_handle64);
- #ifdef CONFIG_PROC_FS
- if (megaCfg->controller_proc_dir_entry) {
- remove_proc_entry ("stat", megaCfg->controller_proc_dir_entry);
- remove_proc_entry ("status",
- megaCfg->controller_proc_dir_entry);
- remove_proc_entry ("config",
- megaCfg->controller_proc_dir_entry);
- remove_proc_entry ("mailbox",
- megaCfg->controller_proc_dir_entry);
- for (i = 0; i < numCtlrs; i++) {
- char buf[12] = { 0 };
- sprintf (buf, "%d", i);
- remove_proc_entry (buf, mega_proc_dir_entry);
- }
- remove_proc_entry ("megaraid", &proc_root);
- }
- #endif
- /*
- * Release the controller memory. A word of warning this frees
- * hostdata and that includes megaCfg-> so be careful what you
- * dereference beyond this point
- */
-
- scsi_unregister (pSHost);
- /*
- * Unregister the character device interface to the driver. Ideally this
- * should have been done in cleanup_module routine. Since this is hidden
- * in file "scsi_module.c", we do it here.
- * major is the major number of the character device returned by call to
- * register_chrdev() routine.
- */
- unregister_chrdev (major, "megadev");
- unregister_reboot_notifier (&mega_notifier);
- return 0;
- }
- static int mega_is_bios_enabled (mega_host_config * megacfg)
- {
- mega_mailbox *mboxpnt;
- unsigned char mbox[16];
- int ret;
- mboxpnt = (mega_mailbox *) mbox;
- memset (mbox, 0, sizeof (mbox));
- memset ((void *) megacfg->mega_buffer,
- 0, sizeof (megacfg->mega_buffer));
- /*
- * issue command to find out if the BIOS is enabled for this controller
- */
- mbox[0] = IS_BIOS_ENABLED;
- mbox[2] = GET_BIOS;
- mboxpnt->xferaddr = virt_to_bus ((void *) megacfg->mega_buffer);
- ret = megaIssueCmd (megacfg, mbox, NULL, 0);
- return (*(char *) megacfg->mega_buffer);
- }
- /*
- * Find out what channels are RAID/SCSI
- */
- void
- mega_enum_raid_scsi(mega_host_config *megacfg)
- {
- mega_mailbox *mboxp;
- unsigned char mbox[16];
- int i;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- dma_addr_t dma_handle;
- #endif
- mboxp = (mega_mailbox *)mbox;
- memset(mbox, 0, sizeof(mbox));
- /*
- * issue command to find out what channels are raid/scsi
- */
- mbox[0] = CHNL_CLASS;
- mbox[2] = GET_CHNL_CLASS;
- memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
- (2 * 1024L), PCI_DMA_FROMDEVICE);
- mboxp->xferaddr = dma_handle;
- #else
- mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
- #endif
- /*
- * Non-ROMB firware fail this command, so all channels
- * must be shown RAID
- */
- if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
- mega_ch_class = *((char *)megacfg->mega_buffer);
- for( i = 0; i < NVIRT_CHAN; i++ ) {
- /* logical drives channel is RAID */
- mega_ch_class |= (0x01 << (megacfg->productInfo.SCSIChanPresent+i));
- }
- }
- else {
- mega_ch_class = 0xFF;
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pci_unmap_single(megacfg->dev, dma_handle,
- (2 * 1024L), PCI_DMA_FROMDEVICE);
- #endif
- }
- /*
- * get the boot logical drive number if enabled
- */
- void
- mega_get_boot_ldrv(mega_host_config *megacfg)
- {
- mega_mailbox *mboxp;
- unsigned char mbox[16];
- struct private_bios_data *prv_bios_data;
- u16 cksum = 0;
- char *cksum_p;
- int i;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- dma_addr_t dma_handle;
- #endif
- mboxp = (mega_mailbox *)mbox;
- memset(mbox, 0, sizeof(mbox));
- mbox[0] = BIOS_PVT_DATA;
- mbox[2] = GET_BIOS_PVT_DATA;
- memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
- (2 * 1024L), PCI_DMA_FROMDEVICE);
- mboxp->xferaddr = dma_handle;
- #else
- mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
- #endif
- megacfg->boot_ldrv_enabled = 0;
- megacfg->boot_ldrv = 0;
- if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
- prv_bios_data = (struct private_bios_data *)megacfg->mega_buffer;
- cksum = 0;
- cksum_p = (char *)prv_bios_data;
- for( i = 0; i < 14; i++ ) {
- cksum += (u16)(*cksum_p++);
- }
- if( prv_bios_data->cksum == (u16)(0-cksum) ) {
- megacfg->boot_ldrv_enabled = 1;
- megacfg->boot_ldrv = prv_bios_data->boot_ldrv;
- }
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pci_unmap_single(megacfg->dev, dma_handle,
- (2 * 1024L), PCI_DMA_FROMDEVICE);
- #endif
- }
- static void mega_reorder_hosts (void)
- {
- struct Scsi_Host *shpnt;
- struct Scsi_Host *shone;
- struct Scsi_Host *shtwo;
- mega_host_config *boot_host;
- int i;
- /*
- * Find the (first) host which has it's BIOS enabled
- */
- boot_host = NULL;
- for (i = 0; i < MAX_CONTROLLERS; i++) {
- if (mega_hbas[i].is_bios_enabled) {
- boot_host = mega_hbas[i].hostdata_addr;
- break;
- }
- }
- if (boot_host == NULL) {
- printk (KERN_WARNING "megaraid: no BIOS enabled.n");
- return;
- }
- /*
- * Traverse through the list of SCSI hosts for our HBA locations
- */
- shone = shtwo = NULL;
- for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
- /* Is it one of ours? */
- for (i = 0; i < MAX_CONTROLLERS; i++) {
- if ((mega_host_config *) shpnt->hostdata ==
- mega_hbas[i].hostdata_addr) {
- /* Does this one has BIOS enabled */
- if (mega_hbas[i].hostdata_addr == boot_host) {
- /* Are we first */
- if (shtwo == NULL) /* Yes! */
- return;
- else { /* :-( */
- shone = shpnt;
- }
- } else {
- if (!shtwo) {
- /* were we here before? xchng first */
- shtwo = shpnt;
- }
- }
- break;
- }
- }
- /*
- * Have we got the boot host and one which does not have the bios
- * enabled.
- */
- if (shone && shtwo)
- break;
- }
- if (shone && shtwo) {
- mega_swap_hosts (shone, shtwo);
- }
- return;
- }
- static void mega_swap_hosts (struct Scsi_Host *shone, struct Scsi_Host *shtwo)
- {
- struct Scsi_Host *prevtoshtwo;
- struct Scsi_Host *prevtoshone;
- struct Scsi_Host *save = NULL;;
- /* Are these two nodes adjacent */
- if (shtwo->next == shone) {
- if (shtwo == scsi_hostlist && shone->next == NULL) {
- /* just two nodes */
- scsi_hostlist = shone;
- shone->next = shtwo;
- shtwo->next = NULL;
- } else if (shtwo == scsi_hostlist) {
- /* first two nodes of the list */
- scsi_hostlist = shone;
- shtwo->next = shone->next;
- scsi_hostlist->next = shtwo;
- } else if (shone->next == NULL) {
- /* last two nodes of the list */
- prevtoshtwo = scsi_hostlist;
- while (prevtoshtwo->next != shtwo)
- prevtoshtwo = prevtoshtwo->next;
- prevtoshtwo->next = shone;
- shone->next = shtwo;
- shtwo->next = NULL;
- } else {
- prevtoshtwo = scsi_hostlist;
- while (prevtoshtwo->next != shtwo)
- prevtoshtwo = prevtoshtwo->next;
- prevtoshtwo->next = shone;
- shtwo->next = shone->next;
- shone->next = shtwo;
- }
- } else if (shtwo == scsi_hostlist && shone->next == NULL) {
- /* shtwo at head, shone at tail, not adjacent */
- prevtoshone = scsi_hostlist;
- while (prevtoshone->next != shone)
- prevtoshone = prevtoshone->next;
- scsi_hostlist = shone;
- shone->next = shtwo->next;
- prevtoshone->next = shtwo;
- shtwo->next = NULL;
- } else if (shtwo == scsi_hostlist && shone->next != NULL) {
- /* shtwo at head, shone is not at tail */
- prevtoshone = scsi_hostlist;
- while (prevtoshone->next != shone)
- prevtoshone = prevtoshone->next;
- scsi_hostlist = shone;
- prevtoshone->next = shtwo;
- save = shtwo->next;
- shtwo->next = shone->next;
- shone->next = save;
- } else if (shone->next == NULL) {
- /* shtwo not at head, shone at tail */
- prevtoshtwo = scsi_hostlist;
- prevtoshone = scsi_hostlist;
- while (prevtoshtwo->next != shtwo)
- prevtoshtwo = prevtoshtwo->next;
- while (prevtoshone->next != shone)
- prevtoshone = prevtoshone->next;
- prevtoshtwo->next = shone;
- shone->next = shtwo->next;
- prevtoshone->next = shtwo;
- shtwo->next = NULL;
- } else {
- prevtoshtwo = scsi_hostlist;
- prevtoshone = scsi_hostlist;
- save = NULL;;
- while (prevtoshtwo->next != shtwo)
- prevtoshtwo = prevtoshtwo->next;
- while (prevtoshone->next != shone)
- prevtoshone = prevtoshone->next;
- prevtoshtwo->next = shone;
- save = shone->next;
- shone->next = shtwo->next;
- prevtoshone->next = shtwo;
- shtwo->next = save;
- }
- return;
- }
- static inline void mega_freeSgList (mega_host_config * megaCfg)
- {
- int i;
- for (i = 0; i < megaCfg->max_cmds; i++) {
- if (megaCfg->scbList[i].sgList)
- pci_free_consistent (megaCfg->dev,
- sizeof (mega_64sglist) *
- MAX_SGLIST,
- megaCfg->scbList[i].sgList,
- megaCfg->scbList[i].
- dma_sghandle64);
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x020400 */
- kfree (megaCfg->scbList[i].sgList); /* free sgList */
- #endif
- }
- }
- /*----------------------------------------------
- * 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,
- "LSI Logic 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;
- char *user_area = NULL;
- megaCfg = (mega_host_config *) SCpnt->host->hostdata;
- DRIVER_LOCK (megaCfg);
- if (!(megaCfg->flag & (1L << SCpnt->channel))) {
- if (SCpnt->channel < megaCfg->productInfo.SCSIChanPresent)
- printk ( KERN_NOTICE
- "scsi%d: scanning channel %d for devices.n",
- megaCfg->host->host_no, SCpnt->channel);
- else
- printk ( KERN_NOTICE
- "scsi%d: scanning virtual channel %d for logical drives.n",
- megaCfg->host->host_no,
- SCpnt->channel-megaCfg->productInfo.SCSIChanPresent+1);
- megaCfg->flag |= (1L << SCpnt->channel);
- }
- SCpnt->scsi_done = pktComp;
- if (mega_driver_ioctl (megaCfg, SCpnt))
- return 0;
- /* 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) {
- /*
- * Check if the HBA is in quiescent state, e.g., during a delete
- * logical drive opertion. If it is, queue the commands in the
- * internal queue until the delete operation is complete.
- */
- if( ! megaCfg->quiescent ) {
- /* 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++;
- if (mega_runpendq (megaCfg) == -1) {
- DRIVER_UNLOCK (megaCfg);
- return 0;
- }
- }
- else {
- /* Add SCB to the internal queue */
- if (megaCfg->int_qh == NULL) {
- megaCfg->int_qh = megaCfg->int_qt = pScb;
- } else {
- megaCfg->int_qt->next = pScb;
- megaCfg->int_qt = pScb;
- }
- megaCfg->int_qt->next = NULL;
- megaCfg->int_qlen++;
- }
- if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
- init_MUTEX_LOCKED (&pScb->ioctl_sem);
- spin_unlock_irq (&io_request_lock);
- down (&pScb->ioctl_sem);
- user_area = (char *)*((u32*)&pScb->SCpnt->cmnd[4]);
- if (copy_to_user
- (user_area, pScb->buff_ptr, pScb->iDataSize)) {
- printk
- ("megaraid: Error copying ioctl return value to user buffer.n");
- pScb->SCpnt->result = (DID_ERROR << 16);
- }
- spin_lock_irq (&io_request_lock);
- DRIVER_LOCK (megaCfg);
- kfree (pScb->buff_ptr);
- pScb->buff_ptr = NULL;
- mega_cmd_done (megaCfg, pScb, pScb->SCpnt->result);
- mega_rundoneq (megaCfg);
- mega_runpendq (megaCfg);
- DRIVER_UNLOCK (megaCfg);
- }
- 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
- *---------------------------------------------------------------------*/
- int megaraid_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 DEBUG
- if (megaCfg->flag & IN_QUEUE)
- printk ("ma:flag is in queuen");
- if (megaCfg->qCompletedH == NULL)
- printk ("ma:qchead == nulln");
- #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 = %xn",
- 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;
- }
- #ifdef CONFIG_PROC_FS
- /* Following code handles /proc fs */
- static int proc_printf (mega_host_config * megaCfg, const char *fmt, ...)
- {
- va_list args;
- int i;
- if (megaCfg->procidx > PROCBUFSIZE)
- return 0;
- va_start (args, fmt);
- i = vsprintf ((megaCfg->procbuf + megaCfg->procidx), fmt, args);
- va_end (args);
- megaCfg->procidx += i;
- return i;
- }
- static int proc_read_config (char *page, char **start, off_t offset,
- int count, int *eof, void *data)
- {
- mega_host_config *megaCfg = (mega_host_config *) data;
- *start = page;
- if (megaCfg->productInfo.ProductName[0] != 0)
- proc_printf (megaCfg, "%sn", megaCfg->productInfo.ProductName);
- proc_printf (megaCfg, "Controller Type: ");
- if (megaCfg->flag & BOARD_QUARTZ)
- proc_printf (megaCfg, "438/466/467/471/493n");
- else
- proc_printf (megaCfg, "418/428/434n");
- if (megaCfg->flag & BOARD_40LD)
- proc_printf (megaCfg,
- "Controller Supports 40 Logical Drivesn");
- if (megaCfg->flag & BOARD_64BIT)
- proc_printf (megaCfg,
- "Controller / Driver uses 64 bit memory addressingn");
- proc_printf (megaCfg, "Base = %08x, Irq = %d, ", megaCfg->base,
- megaCfg->host->irq);
- proc_printf (megaCfg, "Logical Drives = %d, Channels = %dn",
- megaCfg->numldrv, megaCfg->productInfo.SCSIChanPresent);
- proc_printf (megaCfg, "Version =%s:%s, DRAM = %dMbn",
- megaCfg->fwVer, megaCfg->biosVer,
- megaCfg->productInfo.DramSize);
- proc_printf (megaCfg,
- "Controller Queue Depth = %d, Driver Queue Depth = %dn",
- megaCfg->productInfo.MaxConcCmds, megaCfg->max_cmds);
- COPY_BACK;
- return count;
- }
- static int proc_read_stat (char *page, char **start, off_t offset,
- int count, int *eof, void *data)
- {
- int i;
- mega_host_config *megaCfg = (mega_host_config *) data;
- *start = page;
- proc_printf (megaCfg, "Statistical Information for this controllern");
- proc_printf (megaCfg, "Interrupts Collected = %lun",
- megaCfg->nInterrupts);
- for (i = 0; i < megaCfg->numldrv; i++) {
- proc_printf (megaCfg, "Logical Drive %d:n", i);
- proc_printf (megaCfg,
- "tReads Issued = %lu, Writes Issued = %lun",
- megaCfg->nReads[i], megaCfg->nWrites[i]);
- proc_printf (megaCfg,
- "tSectors Read = %lu, Sectors Written = %lunn",
- megaCfg->nReadBlocks[i], megaCfg->nWriteBlocks[i]);
- }
- COPY_BACK;
- return count;
- }
- static int proc_read_status (char *page, char **start, off_t offset,
- int count, int *eof, void *data)
- {
- mega_host_config *megaCfg = (mega_host_config *) data;
- *start = page;
- proc_printf (megaCfg, "TBDn");
- COPY_BACK;
- return count;
- }
- static int proc_read_mbox (char *page, char **start, off_t offset,
- int count, int *eof, void *data)
- {
- mega_host_config *megaCfg = (mega_host_config *) data;
- volatile mega_mailbox *mbox = megaCfg->mbox;
- *start = page;
- proc_printf (megaCfg, "Contents of Mail Box Structuren");
- proc_printf (megaCfg, " Fw Command = 0x%02xn", mbox->cmd);
- proc_printf (megaCfg, " Cmd Sequence = 0x%02xn", mbox->cmdid);
- proc_printf (megaCfg, " No of Sectors= %04dn", mbox->numsectors);
- proc_printf (megaCfg, " LBA = 0x%02xn", mbox->lba);
- proc_printf (megaCfg, " DTA = 0x%08xn", mbox->xferaddr);
- proc_printf (megaCfg, " Logical Drive= 0x%02xn", mbox->logdrv);
- proc_printf (megaCfg, " No of SG Elmt= 0x%02xn", mbox->numsgelements);
- proc_printf (megaCfg, " Busy = %01xn", mbox->busy);
- proc_printf (megaCfg, " Status = 0x%02xn", mbox->status);
- /* proc_printf(megaCfg, "Dump of MailBoxn");
- for (i = 0; i < 16; i++)
- proc_printf(megaCfg, "%02x ",*(mbox + i));
- proc_printf(megaCfg, "nnNumber of Status = %02dn",mbox->numstatus);
- for (i = 0; i < 46; i++) {
- proc_printf(megaCfg,"%02d ",*(mbox + 16 + i));
- if (i%16)
- proc_printf(megaCfg,"n");
- }
- if (!mbox->numsgelements) {
- dta = phys_to_virt(mbox->xferaddr);
- for (i = 0; i < mbox->numsgelements; i++)
- if (dta) {
- proc_printf(megaCfg,"Addr = %08xn", (ulong)*(dta + i)); proc_printf(megaCfg,"Length = %08xn",
- (ulong)*(dta + i + 4));
- }
- }*/
- COPY_BACK;
- return count;
- }
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */
- #define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,
- S_IRUSR | S_IFREG,
- controller_proc_dir_entry,
- fxn, megaCfg)
- #else
- #define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,S_IRUSR | S_IFREG, controller_proc_dir_entry, fxn, megaCfg)
- static struct proc_dir_entry *
- create_proc_read_entry (const char *string,
- int mode,
- struct proc_dir_entry *parent,
- read_proc_t * fxn, mega_host_config * megaCfg)
- {
- struct proc_dir_entry *temp = NULL;
- temp = kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
- if (!temp)
- return NULL;
- memset (temp, 0, sizeof (struct proc_dir_entry));
- if ((temp->name = kmalloc (strlen (string) + 1, GFP_KERNEL)) == NULL) {
- kfree (temp);
- return NULL;
- }
- strcpy ((char *) temp->name, string);
- temp->namelen = strlen (string);
- temp->mode = mode; /*S_IFREG | S_IRUSR */ ;
- temp->data = (void *) megaCfg;
- temp->read_proc = fxn;
- proc_register (parent, temp);
- return temp;
- }
- #endif
- static void mega_create_proc_entry (int index, struct proc_dir_entry *parent)
- {
- u_char string[64] = { 0 };
- mega_host_config *megaCfg = megaCtlrs[index];
- struct proc_dir_entry *controller_proc_dir_entry = NULL;
- sprintf (string, "%d", index);
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */
- controller_proc_dir_entry =
- megaCfg->controller_proc_dir_entry = proc_mkdir (string, parent);
- #else
- controller_proc_dir_entry =
- megaCfg->controller_proc_dir_entry =
- create_proc_entry (string, S_IFDIR | S_IRUGO | S_IXUGO, parent);
- #endif
- if (!controller_proc_dir_entry)
- printk ("nmegaraid: proc_mkdir failedn");
- else {
- megaCfg->proc_read =
- CREATE_READ_PROC ("config", proc_read_config);
- megaCfg->proc_status =
- CREATE_READ_PROC ("status", proc_read_status);
- megaCfg->proc_stat = CREATE_READ_PROC ("stat", proc_read_stat);
- megaCfg->proc_mbox =
- CREATE_READ_PROC ("mailbox", proc_read_mbox);
- }
- }
- #endif /* CONFIG_PROC_FS */
- /*-------------------------------------------------------------
- * 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;
- if( IS_RAID_CH(disk->device->channel)) {
- /* 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;
- }
- else {
- if( mega_partsize(disk, dev, geom) == 0 ) return 0;
- printk(KERN_WARNING
- "megaraid: invalid partition on this disk on channel %dn",
- disk->device->channel);
- /* 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;
- }
- /*
- * Function : static int mega_partsize(Disk * disk, kdev_t dev, int *geom)
- *
- * Purpose : to determine the BIOS mapping used to create the partition
- * table, storing the results (cyls, hds, and secs) in geom
- *
- * Note: Code is picked from scsicam.h
- *
- * Returns : -1 on failure, 0 on success.
- */
- static int
- mega_partsize(Disk * disk, kdev_t dev, int *geom)
- {
- struct buffer_head *bh;
- struct partition *p, *largest = NULL;
- int i, largest_cyl;
- int heads, cyls, sectors;
- int capacity = disk->capacity;
- if(!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
- return -1;
- if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
- for( largest_cyl = -1, p = (struct partition *)(0x1BE + bh->b_data),
- i = 0; i < 4; ++i, ++p) {
- if (!p->sys_ind) continue;
- cyls = p->end_cyl + ((p->end_sector & 0xc0) << 2);
- if(cyls >= largest_cyl) {
- largest_cyl = cyls;
- largest = p;
- }
- }
- }
- if (largest) {
- heads = largest->end_head + 1;
- sectors = largest->end_sector & 0x3f;
- if (heads == 0 || sectors == 0) {
- brelse(bh);
- return -1;
- }
- cyls = capacity/(heads * sectors);
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cyls;
- brelse(bh);
- return 0;
- }
- brelse(bh);
- return -1;
- }
- /*
- * This routine will be called when the use has done a forced shutdown on the
- * system. Flush the Adapter cache, that's the most we can do.
- */
- static int megaraid_reboot_notify (struct notifier_block *this, unsigned long code,
- void *unused)
- {
- struct Scsi_Host *pSHost;
- mega_host_config *megaCfg;
- mega_mailbox *mbox;
- u_char mboxData[16];
- int i;
- if (code == SYS_DOWN || code == SYS_HALT) {
- for (i = 0; i < numCtlrs; i++) {
- pSHost = megaCtlrs[i]->host;
- megaCfg = (mega_host_config *) pSHost->hostdata;
- mbox = (mega_mailbox *) mboxData;
- /* Flush cache to disk */
- memset (mbox, 0, 16);
- mboxData[0] = 0xA;
- /*
- * Free irq, otherwise extra interrupt is generated
- */
- free_irq (megaCfg->host->irq, megaCfg);
- /*
- * Issue a blocking (interrupts disabled) command to
- * the card
- */
- megaIssueCmd (megaCfg, mboxData, NULL, 0);
- }
- }
- return NOTIFY_DONE;
- }
- static int mega_init_scb (mega_host_config * megacfg)
- {
- int idx;
- #if DEBUG
- if (megacfg->max_cmds >= MAX_COMMANDS) {
- printk ("megaraid:ctlr max cmds = %x : MAX_CMDS = %x",
- megacfg->max_cmds, MAX_COMMANDS);
- }
- #endif
- for (idx = megacfg->max_cmds - 1; idx >= 0; idx--) {
- megacfg->scbList[idx].idx = idx;
- /*
- * ISR will make this flag zero to indicate the command has been
- * completed. This is only for user ioctl calls. Rest of the driver
- * and the mid-layer operations are not connected with this flag.
- */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- megacfg->scbList[idx].sgList =
- pci_alloc_consistent (megacfg->dev,
- sizeof (mega_64sglist) * MAX_SGLIST,
- &(megacfg->scbList[idx].
- dma_sghandle64));
- megacfg->scbList[idx].sg64List =
- (mega_64sglist *) megacfg->scbList[idx].sgList;
- #else
- megacfg->scbList[idx].sgList = kmalloc (sizeof (mega_sglist) * MAX_SGLIST, GFP_ATOMIC | GFP_DMA);
- #endif
- if (megacfg->scbList[idx].sgList == NULL) {
- printk (KERN_WARNING
- "Can't allocate sglist for id %dn", idx);
- mega_freeSgList (megacfg);
- return -1;
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- megacfg->scbList[idx].pthru = pci_alloc_consistent (megacfg->dev,
- sizeof (mega_passthru),
- &(megacfg->scbList[idx].
- dma_passthruhandle64));
- if (megacfg->scbList[idx].pthru == NULL) {
- printk (KERN_WARNING
- "Can't allocate passthru for id %dn", idx);
- }
- megacfg->scbList[idx].epthru =
- pci_alloc_consistent(
- megacfg->dev, sizeof(mega_ext_passthru),
- &(megacfg->scbList[idx].dma_ext_passthruhandle64)
- );
- if (megacfg->scbList[idx].epthru == NULL) {
- printk (KERN_WARNING
- "Can't allocate extended passthru for id %dn", idx);
- }
- /*
- * Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA
- */
- megacfg->scbList[idx].bounce_buffer = pci_alloc_consistent (megacfg->dev,
- 256,
- &(megacfg->scbList[idx].
- dma_bounce_buffer));
- if (!megacfg->scbList[idx].bounce_buffer)
- printk
- ("megaraid: allocation for bounce buffer failedn");
- megacfg->scbList[idx].dma_type = M_RD_DMA_TYPE_NONE;
- #endif
- if (idx < MAX_COMMANDS) {
- /*
- * Link to free list
- * lock not required since we are loading the driver, so no
- * commands possible right now.
- */
- enq_scb_freelist (megacfg, &megacfg->scbList[idx],
- NO_LOCK, INTR_ENB);
- }
- }
- return 0;
- }
- /*
- * Enqueues a SCB
- */
- static void enq_scb_freelist (mega_host_config * megacfg, mega_scb * scb, int lock,
- int intr)
- {
- if (lock == INTERNAL_LOCK || intr == INTR_DIS) {
- if (intr == INTR_DIS)
- spin_lock_irq (&megacfg->lock_free);
- else
- spin_lock (&megacfg->lock_free);
- }
- scb->state = SCB_FREE;
- scb->SCpnt = NULL;
- if (megacfg->qFreeH == (mega_scb *) NULL) {
- megacfg->qFreeH = megacfg->qFreeT = scb;
- } else {
- megacfg->qFreeT->next = scb;
- megacfg->qFreeT = scb;
- }
- megacfg->qFreeT->next = NULL;
- megacfg->qFcnt++;
- if (lock == INTERNAL_LOCK || intr == INTR_DIS) {
- if (intr == INTR_DIS)
- spin_unlock_irq (&megacfg->lock_free);
- else
- spin_unlock (&megacfg->lock_free);
- }
- }
- /*
- * Routines for the character/ioctl interface to the driver
- */
- static int megadev_open (struct inode *inode, struct file *filep)
- {
- MOD_INC_USE_COUNT;
- return 0; /* success */
- }
- static int megadev_ioctl_entry (struct inode *inode, struct file *filep,
- unsigned int cmd, unsigned long arg)
- {
- int ret = -1;
- /*
- * We do not allow parallel ioctls to the driver as of now.
- */
- down (&mimd_entry_mtx);
- ret = megadev_ioctl (inode, filep, cmd, arg);
- up (&mimd_entry_mtx);
- return ret;
- }
- static int megadev_ioctl (struct inode *inode, struct file *filep,
- unsigned int cmd, unsigned long arg)
- {
- int adapno;
- kdev_t dev;
- u32 inlen;
- struct uioctl_t ioc;
- char *kvaddr = NULL;
- int nadap = numCtlrs;
- u8 opcode;
- u32 outlen;
- int ret;
- u8 subopcode;
- Scsi_Cmnd *scsicmd;
- struct Scsi_Host *shpnt;
- char *uaddr;
- struct uioctl_t *uioc;
- dma_addr_t dma_addr;
- u32 length;
- mega_host_config *megacfg = NULL;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */
- struct pci_dev pdev;
- struct pci_dev *pdevp = &pdev;
- #else
- char *pdevp = NULL;
- #endif
- IO_LOCK_T;
- if (!inode || !(dev = inode->i_rdev))
- return -EINVAL;
- if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC)
- return (-EINVAL);
- /*
- * Get the user ioctl structure
- */
- ret = verify_area (VERIFY_WRITE, (char *) arg, sizeof (struct uioctl_t));
- if (ret)
- return ret;
- if(copy_from_user (&ioc, (char *) arg, sizeof (struct uioctl_t)))
- return -EFAULT;
- /*
- * The first call the applications should make is to find out the
- * number of controllers in the system. The next logical call should
- * be for getting the list of controllers in the system as detected
- * by the driver.
- */
- /*
- * Get the opcode and subopcode for the commands
- */
- opcode = ioc.ui.fcs.opcode;
- subopcode = ioc.ui.fcs.subopcode;
- switch (opcode) {
- case M_RD_DRIVER_IOCTL_INTERFACE:
- switch (subopcode) {
- case MEGAIOC_QDRVRVER: /* Query driver version */
- put_user (driver_ver, (u32 *) ioc.data);
- return 0;
- case MEGAIOC_QNADAP: /* Get # of adapters */
- put_user (nadap, (int *) ioc.data);
- return nadap;
- case MEGAIOC_QADAPINFO: /* Get adapter information */
- /*
- * which adapter?
- */
- adapno = ioc.ui.fcs.adapno;
- /*
- * The adapter numbers do not start with 0, at least in
- * the user space. This is just to make sure, 0 is not the
- * default value which will refer to adapter 1. So the
- * user needs to make use of macros MKADAP() and GETADAP()
- * (See megaraid.h) while making ioctl() call.
- */
- adapno = GETADAP (adapno);
- if (adapno >= numCtlrs)
- return (-ENODEV);
- ret = verify_area (VERIFY_WRITE,
- ioc.data,
- sizeof (struct mcontroller));
- if (ret)
- return ret;
- /*
- * Copy struct mcontroller to user area
- */
- copy_to_user (ioc.data,
- mcontroller + adapno,
- sizeof (struct mcontroller));
- return 0;
- default:
- return (-EINVAL);
- } /* inner switch */
- break;
- case M_RD_IOCTL_CMD_NEW:
- /*
- * Deletion of logical drives is only handled in 0x80 commands
- */
- if( ioc.mbox[0] == FC_DEL_LOGDRV && ioc.mbox[2] == OP_DEL_LOGDRV ) {
- return -EINVAL;
- }
- /* which adapter? */
- adapno = ioc.ui.fcs.adapno;
- /* See comment above: MEGAIOC_QADAPINFO */
- adapno = GETADAP(adapno);
- if (adapno >= numCtlrs)
- return(-ENODEV);
- length = ioc.ui.fcs.length;
- /* Check for zero length buffer or very large buffers */
- if( !length || length > 32*1024 )
- return -EINVAL;
- /* save the user address */
- uaddr = ioc.ui.fcs.buffer;
- /*
- * For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of
- * uioctl_t structure are treated as flags. If outlen is 1, the
- * data is transferred from the device and if inlen is 1, the data
- * is transferred to the device.
- */
- outlen = ioc.outlen;
- inlen = ioc.inlen;
- if(outlen) {
- ret = verify_area(VERIFY_WRITE, (char *)ioc.ui.fcs.buffer, length);
- if (ret) return ret;
- }
- if(inlen) {
- ret = verify_area(VERIFY_READ, (char *) ioc.ui.fcs.buffer, length);
- if (ret) return ret;
- }
- /*
- * Find this host
- */
- for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) {
- if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
- megacfg = (mega_host_config *)shpnt->hostdata;
- break;
- }
- }
- if(shpnt == NULL) return -ENODEV;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
- #else
- scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
- GFP_ATOMIC | GFP_DMA);
- #endif
- if(scsicmd == NULL) return -ENOMEM;
- memset(scsicmd, 0, sizeof(Scsi_Cmnd));
- scsicmd->host = shpnt;
- if( outlen || inlen ) {
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pdevp = &pdev;
- memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev));
- pdevp->dma_mask = 0xffffffff;
- #else
- pdevp = NULL;
- #endif
- kvaddr = dma_alloc_consistent(pdevp, length, &dma_addr);
- if( kvaddr == NULL ) {
- printk(KERN_WARNING "megaraid:allocation failedn");
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */
- kfree(scsicmd);
- #else
- scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
- #endif
- return -ENOMEM;
- }
- ioc.ui.fcs.buffer = kvaddr;
- if (inlen) {
- /* copyin the user data */
- copy_from_user(kvaddr, (char *)uaddr, length );
- }
- }
- scsicmd->cmnd[0] = MEGADEVIOC;
- scsicmd->request_buffer = (void *)&ioc;
- init_MUTEX_LOCKED(&mimd_ioctl_sem);
- IO_LOCK;
- megaraid_queue(scsicmd, megadev_ioctl_done);
- IO_UNLOCK;
- down(&mimd_ioctl_sem);
- if( !scsicmd->result && outlen ) {
- copy_to_user(uaddr, kvaddr, length);
- }
- /*
- * copyout the result
- */
- uioc = (struct uioctl_t *)arg;
- if( ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
- put_user( scsicmd->result, &uioc->pthru.scsistatus );
- } else {
- put_user(1, &uioc->mbox[16]); /* numstatus */
- /* status */
- put_user (scsicmd->result, &uioc->mbox[17]);
- }
- if (kvaddr) {
- dma_free_consistent(pdevp, length, kvaddr, dma_addr);
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */
- kfree (scsicmd);
- #else
- scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
- #endif
- /* restore the user address */
- ioc.ui.fcs.buffer = uaddr;
- return ret;
- case M_RD_IOCTL_CMD:
- /* which adapter? */
- adapno = ioc.ui.fcs.adapno;
- /* See comment above: MEGAIOC_QADAPINFO */
- adapno = GETADAP (adapno);
- if (adapno >= numCtlrs)
- return (-ENODEV);
- /* save the user address */
- uaddr = ioc.data;
- outlen = ioc.outlen;
- inlen = ioc.inlen;
- if ((outlen >= IOCTL_MAX_DATALEN) || (inlen >= IOCTL_MAX_DATALEN))
- return (-EINVAL);
- if (outlen) {
- ret = verify_area (VERIFY_WRITE, ioc.data, outlen);
- if (ret) return ret;
- }
- if (inlen) {
- ret = verify_area (VERIFY_READ, ioc.data, inlen);
- if (ret) return ret;
- }
- /*
- * Find this host
- */
- for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) {
- if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
- megacfg = (mega_host_config *)shpnt->hostdata;
- break;
- }
- }
- if(shpnt == NULL) return -ENODEV;
- /*
- * ioctls for deleting logical drives is a special case, so check
- * for it first
- */
- if( ioc.mbox[0] == FC_DEL_LOGDRV && ioc.mbox[2] == OP_DEL_LOGDRV ) {
- if( !megacfg->support_random_del ) {
- printk("megaraid: logdrv delete on non supporting f/w.n");
- return -EINVAL;
- }
- uioc = (struct uioctl_t *)arg;
- ret = mega_del_logdrv(megacfg, ioc.mbox[3]);
- put_user(1, &uioc->mbox[16]); /* numstatus */
- put_user(ret, &uioc->mbox[17]); /* status */
- /* if deletion failed, let the user know by failing ioctl */
- return ret;
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
- #else
- scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
- GFP_ATOMIC | GFP_DMA);
- #endif
- if(scsicmd == NULL) return -ENOMEM;
- memset(scsicmd, 0, sizeof(Scsi_Cmnd));
- scsicmd->host = shpnt;
- if (outlen || inlen) {
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pdevp = &pdev;
- memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev));
- pdevp->dma_mask = 0xffffffff;
- #else
- pdevp = NULL;
- #endif
- /*
- * Allocate a page of kernel space.
- */
- kvaddr = dma_alloc_consistent(pdevp, PAGE_SIZE, &dma_addr);
- if( kvaddr == NULL ) {
- printk (KERN_WARNING "megaraid:allocation failedn");
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */
- kfree(scsicmd);
- #else
- scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
- #endif
- return -ENOMEM;
- }
- ioc.data = kvaddr;
- if (inlen) {
- if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
- /* copyin the user data */
- copy_from_user (kvaddr, uaddr, ioc.pthru.dataxferlen);
- } else {
- copy_from_user (kvaddr, uaddr, inlen);
- }
- }
- }
- scsicmd->cmnd[0] = MEGADEVIOC;
- scsicmd->request_buffer = (void *) &ioc;
- init_MUTEX_LOCKED (&mimd_ioctl_sem);
- IO_LOCK;
- megaraid_queue (scsicmd, megadev_ioctl_done);
- IO_UNLOCK;
- down (&mimd_ioctl_sem);
- if (!scsicmd->result && outlen) {
- if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
- copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen);
- } else {
- copy_to_user (uaddr, kvaddr, outlen);
- }
- }
- /*
- * copyout the result
- */
- uioc = (struct uioctl_t *) arg;
- if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
- put_user (scsicmd->result, &uioc->pthru.scsistatus);
- } else {
- put_user (1, &uioc->mbox[16]); /* numstatus */
- put_user (scsicmd->result, &uioc->mbox[17]); /* status */
- }
- if (kvaddr) {
- dma_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr );
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- kfree (scsicmd);
- #else
- scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
- #endif
- /* restore user pointer */
- ioc.data = uaddr;
- return ret;
- default:
- return (-EINVAL);
- }/* Outer switch */
- return 0;
- }
- static void
- megadev_ioctl_done(Scsi_Cmnd *sc)
- {
- up (&mimd_ioctl_sem);
- }
- static mega_scb *
- megadev_doioctl (mega_host_config * megacfg, Scsi_Cmnd * sc)
- {
- u8 cmd;
- struct uioctl_t *ioc = NULL;
- mega_mailbox *mbox = NULL;
- mega_ioctl_mbox *mboxioc = NULL;
- struct mbox_passthru *mboxpthru = NULL;
- mega_scb *scb = NULL;
- mega_passthru *pthru = NULL;
- if ((scb = mega_allocateSCB (megacfg, sc)) == NULL) {
- sc->result = (DID_ERROR << 16);
- callDone (sc);
- return NULL;
- }
- ioc = (struct uioctl_t *) sc->request_buffer;
- memcpy (scb->mboxData, ioc->mbox, sizeof (scb->mboxData));
- /* The generic mailbox */
- mbox = (mega_mailbox *) ioc->mbox;
- /*
- * Get the user command
- */
- cmd = ioc->mbox[0];
- switch (cmd) {
- case MEGA_MBOXCMD_PASSTHRU:
- /*
- * prepare the SCB with information from the user ioctl structure
- */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pthru = scb->pthru;
- #else
- pthru = &scb->pthru;
- #endif
- memcpy (pthru, &ioc->pthru, sizeof (mega_passthru));
- mboxpthru = (struct mbox_passthru *) scb->mboxData;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- if (megacfg->flag & BOARD_64BIT) {
- /* This is just a sample with one element
- * This if executes onlu on 2.4 kernels
- */
- mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
- scb->sg64List[0].address =
- pci_map_single (megacfg->dev,
- ioc->data,
- 4096, PCI_DMA_BIDIRECTIONAL);
- scb->sg64List[0].length = 4096; // TODO: Check this
- pthru->dataxferaddr = scb->dma_sghandle64;
- pthru->numsgelements = 1;
- mboxpthru->cmd = 0xC3;
- } else {
- mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
- pthru->dataxferaddr =
- pci_map_single (megacfg->dev,
- ioc->data,
- 4096, PCI_DMA_BIDIRECTIONAL);
- pthru->numsgelements = 0;
- }
- #else
- {
- mboxpthru->dataxferaddr = virt_to_bus (&scb->pthru);
- pthru->dataxferaddr = virt_to_bus (ioc->data);
- pthru->numsgelements = 0;
- }
- #endif
- pthru->reqsenselen = 14;
- break;
- default: /* Normal command */
- mboxioc = (mega_ioctl_mbox *) scb->mboxData;
- if (ioc->ui.fcs.opcode == M_RD_IOCTL_CMD_NEW) {
- scb->buff_ptr = ioc->ui.fcs.buffer;
- scb->iDataSize = ioc->ui.fcs.length;
- } else {
- scb->buff_ptr = ioc->data;
- scb->iDataSize = 4096; // TODO:check it
- }
- set_mbox_xfer_addr (megacfg, scb, mboxioc, FROMTO_DEVICE);
- mboxioc->numsgelements = 0;
- break;
- }
- return scb;
- }
- static int
- megadev_close (struct inode *inode, struct file *filep)
- {
- #ifdef MODULE
- MOD_DEC_USE_COUNT;
- #endif
- return 0;
- }
- static int
- mega_support_ext_cdb(mega_host_config *this_hba)
- {
- mega_mailbox *mboxpnt;
- unsigned char mbox[16];
- int ret;
- mboxpnt = (mega_mailbox *) mbox;
- memset(mbox, 0, sizeof (mbox));
- /*
- * issue command to find out if controller supports extended CDBs.
- */
- mbox[0] = 0xA4;
- mbox[2] = 0x16;
- ret = megaIssueCmd(this_hba, mbox, NULL, 0);
- return !ret;
- }
- /*
- * Find out if this controller supports random deletion and addition of
- * logical drives
- */
- static int
- mega_support_random_del(mega_host_config *this_hba)
- {
- mega_mailbox *mboxpnt;
- unsigned char mbox[16];
- int ret;
- mboxpnt = (mega_mailbox *)mbox;
- memset(mbox, 0, sizeof(mbox));
- /*
- * issue command
- */
- mbox[0] = FC_DEL_LOGDRV;
- mbox[2] = OP_SUP_DEL_LOGDRV;
- ret = megaIssueCmd(this_hba, mbox, NULL, 0);
- return !ret;
- }
- static int
- mega_del_logdrv(mega_host_config *this_hba, int logdrv)
- {
- int rval;
- IO_LOCK_T;
- DECLARE_WAIT_QUEUE_HEAD(wq);
- mega_scb *scbp;
- /*
- * Stop sending commands to the controller, queue them internally.
- * When deletion is complete, ISR will flush the queue.
- */
- IO_LOCK;
- this_hba->quiescent = 1;
- IO_UNLOCK;
- while( this_hba->qPcnt ) {
- sleep_on_timeout( &wq, 1*HZ ); /* sleep for 1s */
- }
- rval = mega_do_del_logdrv(this_hba, logdrv);
- IO_LOCK;
- /*
- * Attach the internal queue to the pending queue
- */
- if( this_hba->qPendingH == NULL ) {
- /*
- * If pending queue head is null, make internal queue as
- * pending queue
- */
- this_hba->qPendingH = this_hba->int_qh;
- this_hba->qPendingT = this_hba->int_qt;
- this_hba->qPcnt = this_hba->int_qlen;
- }
- else {
- /*
- * Append pending queue to internal queue
- */
- if( this_hba->int_qt ) {
- this_hba->int_qt->next = this_hba->qPendingH;
- this_hba->qPendingH = this_hba->int_qh;
- this_hba->qPcnt += this_hba->int_qlen;
- }
- }
- this_hba->int_qh = this_hba->int_qt = NULL;
- this_hba->int_qlen = 0;
- /*
- * If delete operation was successful, add 0x80 to the logical drive
- * ids for commands in the pending queue.
- */
- if( this_hba->read_ldidmap) {
- for( scbp = this_hba->qPendingH; scbp; scbp = scbp->next ) {
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- if( scbp->pthru->logdrv < 0x80 )
- scbp->pthru->logdrv += 0x80;
- #else
- if( scbp->pthru.logdrv < 0x80 )
- scbp->pthru.logdrv += 0x80;
- #endif
- }
- }
- this_hba->quiescent = 0;
- IO_UNLOCK;
- return rval;
- }
- static int
- mega_do_del_logdrv(mega_host_config *this_hba, int logdrv)
- {
- mega_mailbox *mboxpnt;
- unsigned char mbox[16];
- int rval;
- mboxpnt = (mega_mailbox *)mbox;
- memset(mbox, 0, sizeof(mbox));
- mbox[0] = FC_DEL_LOGDRV;
- mbox[2] = OP_DEL_LOGDRV;
- mbox[3] = logdrv;
- rval = megaIssueCmd(this_hba, mbox, NULL, 0);
- /* log this event */
- if( rval != 0 ) {
- printk("megaraid: Attempt to delete logical drive %d failed.",
- logdrv);
- return rval;
- }
- printk("megaraid: logical drive %d deleted.n", logdrv);
- /*
- * After deleting first logical drive, the logical drives must be
- * addressed by adding 0x80 to the logical drive id.
- */
- this_hba->read_ldidmap = 1;
- return rval;
- }
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
- void *
- dma_alloc_consistent(void *dev, size_t size, dma_addr_t *dma_addr)
- {
- void *_tv;
- int npages;
- int order = 0;
- /*
- * How many pages application needs
- */
- npages = size / PAGE_SIZE;
- /* Do we need one more page */
- if(size % PAGE_SIZE)
- npages++;
- order = mega_get_order(npages);
- _tv = (void *)__get_free_pages(GFP_DMA, order);
- if( _tv != NULL ) {
- memset(_tv, 0, size);
- *(dma_addr) = virt_to_bus(_tv);
- }
- return _tv;
- }
- /*
- * int mega_get_order(int)
- *
- * returns the order to be used as 2nd argument to __get_free_pages() - which
- * return pages equal to pow(2, order) - AM
- */
- int
- mega_get_order(int n)
- {
- int i = 0;
- while( pow_2(i++) < n )
- ; /* null statement */
- return i-1;
- }
- /*
- * int pow_2(int)
- *
- * calculates pow(2, i)
- */
- int
- pow_2(int i)
- {
- unsigned int v = 1;
-
- while(i--)
- v <<= 1;
- return v;
- }
- void
- dma_free_consistent(void *dev, size_t size, void *vaddr, dma_addr_t dma_addr)
- {
- int npages;
- int order = 0;
- npages = size / PAGE_SIZE;
- if(size % PAGE_SIZE)
- npages++;
- if (npages == 1)
- order = 0;
- else if (npages == 2)
- order = 1;
- else if (npages <= 4)
- order = 2;
- else
- order = 3;
- free_pages((unsigned long)vaddr, order);
- }
- #endif
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- static
- #endif /* LINUX VERSION 2.4.XX */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE)
- Scsi_Host_Template driver_template = MEGARAID;
- #include "scsi_module.c"
- #endif /* LINUX VERSION 2.4.XX || MODULE */
- /* vi: set ts=4: */