📄 qla2x00.c
字号:
* qla2100_detect** Description:* This routine will probe for Qlogic FC SCSI host adapters.* It returns the number of host adapters of a particular* type that were found. It also initialize all data necessary for* the driver. It is passed-in the host number, so that it* knows where its first entry is in the scsi_hosts[] array.** Input:* template - pointer to SCSI template** Returns:* num - number of host adapters found.**************************************************************************/intqla2100_detect(Scsi_Host_Template *template) { int num_hosts = 0; struct Scsi_Host *host; scsi_qla_host_t *ha, *cur_ha; struct _qlaboards *bdp; int i, j;#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,95) unsigned int piobase; unsigned char pci_bus, pci_devfn, pci_irq; config_reg_t *cfgp = 0;#endif device_reg_t *reg; char *cp;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) struct pci_dev *pdev = NULL;#else int index;#endif struct semaphore sem = MUTEX_LOCKED; unsigned long wait_switch = 0; ENTER("qla2100_detect");#ifdef CODECHECK if( sizeof(srb_t) > sizeof(Scsi_Pointer) ) { printk("Redefine SRB - its too big"); return 0; }#endif#ifdef MODULE DEBUG2(sprintf(debug_buff,"DEBUG: qla2100_detect starts at address = 0x%8lx\n",(uint32_t)qla2100_detect);) DEBUG2(qla2100_print(debug_buff);) /* * If we are called as a module, the qla2100 pointer may not be null * and it would point to our bootup string, just like on the lilo * command line. IF not NULL, then process this config string with * qla2100_setup * * Boot time Options * To add options at boot time add a line to your lilo.conf file like: * append="qla2100=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}" * which will result in the first four devices on the first two * controllers being set to a tagged queue depth of 32. */ if( ql2xopts ) qla2100_setup(ql2xopts, NULL); if( dummy_buffer[0] != 'P' ) printk(KERN_WARNING "qla2100: Please read the file /usr/src/linux/drivers" "/scsi/README.qla2100\n" "qla2100: to see the proper way to specify options to the qla2100 " "module\n" "qla2100: Specifically, don't use any commas when passing arguments to\n" "qla2100: insmod or else it might trash certain memory areas.\n");#endif if( (int) !pcibios_present() ) { printk("scsi: PCI not present\n"); return 0; } /* end of IF */ bdp = &QLBoardTbl[0]; qla2100_hostlist = NULL; template->proc_dir = &proc_scsi_qla2100; /* Try and find each different type of adapter we support */ for( i=0; bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES; i++, bdp++ ) {#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) while( (pdev = pci_find_device(QLA2100_VENDOR_ID, bdp->device_id, pdev) ) ) { /* found a adapter */#else while( !(pcibios_find_device(QLA2100_VENDOR_ID, bdp->device_id, index++, &pci_bus, &pci_devfn)) ) { /* found a adapter */#endif host = scsi_register(template, sizeof(scsi_qla_host_t)); ha = (scsi_qla_host_t *) host->hostdata; /* Clear our data area */ /* tt 1/18/00 */ for( j =0, cp = (char *)ha; j < sizeof(scsi_qla_host_t); j++, cp++ ) *cp = 0; /* Sanitize the information from PCI BIOS. */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) host->irq = pdev->irq; host->io_port = (unsigned int) pdev->base_address[0]; ha->pci_bus = pdev->bus->number; ha->pci_device_fn = pdev->devfn; ha->pdev = pdev;#else pcibios_read_config_byte(pci_bus, pci_devfn, OFFSET(cfgp->interrupt_line), &pci_irq); pcibios_read_config_dword(pci_bus, pci_devfn, OFFSET(cfgp->base_port), &piobase); host->irq = pci_irq; host->io_port = (unsigned int) piobase; ha->pci_bus = pci_bus; ha->pci_device_fn = pci_devfn;#endif ha->device_id = bdp->device_id; host->io_port &= PCI_BASE_ADDRESS_IO_MASK; ha->devnum = i; if( qla2100_verbose ) { printk("(scsi): Found a %s @ bus %d, device %d, irq %d, iobase 0x%x\n", bdp->bdName,ha->pci_bus, (ha->pci_device_fn & 0xf8) >> 3, host->irq,(int)host->io_port); } ha->iobase = (device_reg_t *) host->io_port; ha->host = host; if( qla2100_mem_alloc(ha) ) { printk(KERN_INFO "qla2100: Failed to allocate memory for adapter\n"); } ha->prev_topology = 0; ha->ports = bdp->numPorts; ha->host_no = host->host_no; if( ha->device_id == QLA2100_DEVICE_ID ) ha->max_targets = MAX_TARGETS_2100; else ha->max_targets = MAX_TARGETS_2200; /* load the F/W, read paramaters, and init the H/W */ ha->instance = num_hosts; if( qla2100_initialize_adapter(ha) ) { printk(KERN_INFO "qla2100: Failed to initialized adapter\n"); qla2100_mem_free(ha); scsi_unregister(host); continue; } ha->next = NULL; /* Mark preallocated Loop IDs in use. */ ha->fabricid[SNS_FL_PORT].in_use = TRUE; ha->fabricid[FABRIC_CONTROLLER].in_use = TRUE; ha->fabricid[SIMPLE_NAME_SERVER].in_use = TRUE; /* Register our resources with Linux */ if( qla2100_register_with_Linux(ha, bdp->numPorts-1) ) { printk(KERN_INFO "qla2100: Failed to register our resources\n"); qla2100_mem_free(ha); scsi_unregister(host); continue; } reg = ha->iobase; /* Disable ISP interrupts. */ qla2100_disable_intrs(ha); /* * Startup the kernel thread for this host adapter */ ha->dpc_notify = &sem; kernel_thread((int (*)(void *))qla2100_do_dpc, (void *) ha, 0); /* * Now wait for the kernel dpc thread to initialize and go to sleep. */ down(&sem); ha->dpc_notify = NULL; /* * These locks are used to prevent more than one CPU from modifying the queue at * the same time. The higher level "io_request_lock" will reduce most contention * for these locks. */ ha->retry_lock = SPIN_LOCK_UNLOCKED; /* Insure mailbox registers are free. */ WRT_REG_WORD(®->semaphore, 0); WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); /* Wait around max 5 secs for the devices to come on-line */ /* we don't want Linux scanning before we are ready */ /* v2.19.5b6 */ for (wait_switch = jiffies + (ha->loop_reset_delay * HZ); wait_switch > jiffies && !(ha->device_flags & DFLG_FABRIC_DEVICES) ;) { qla2100_check_fabric_devices(ha); } /* just in case we turned it on */ ha->dpc_flags &= ~COMMAND_WAIT_NEEDED; /* List the target we have found */ qla2100_display_fc_names(ha); /* Enable chip interrupts. */ qla2100_enable_intrs(ha); /* Insert new entry into the list of adapters */ ha->next = NULL; if( qla2100_hostlist == NULL ) { qla2100_hostlist = ha; } else { cur_ha = qla2100_hostlist; while( cur_ha->next != NULL ) cur_ha = cur_ha->next; cur_ha->next = ha; } num_hosts++; } } /* end of FOR */ LEAVE("qla2100_detect"); return num_hosts; } /************************************************************************** * qla2100_register_with_Linux * * Description: * Free the passed in Scsi_Host memory structures prior to unloading the * module. * * Input: * ha - pointer to host adapter structure * maxchannels - MAX number of channels. * * Returns: * 0 - Sucessfully reserved resources. * 1 - Failed to reserved a resource. **************************************************************************/ static uint8_t qla2100_register_with_Linux(scsi_qla_host_t *ha, uint8_t maxchannels) { struct Scsi_Host *host = ha->host; char drvname[9]; host->can_queue = 0xfffff; /* unlimited */ host->cmd_per_lun = 1; host->select_queue_depths = qla2100_select_queue_depth; host->n_io_port = 0xFF; host->base = (unsigned char *) ha->mmpbase; host->max_channel = maxchannels; /* fix: 07/31 host->max_lun = MAX_LUNS-1; */ host->max_lun = ha->max_luns; host->unique_id = ha->instance; host->max_id = ha->max_targets; /* set our host ID (need to do something about our two IDs) */ host->this_id = 255; /* ER# 4368 */ sprintf(drvname,"qla2x00#%02d",host->unique_id); /* Register the IRQ with Linux (sharable) */ if( request_irq(host->irq, qla2100_intr_handler, SA_INTERRUPT| SA_SHIRQ, "qla2x00", ha) ) { printk("qla2100 : Failed to reserved interrupt %d already in use\n", host->irq); return 1; } /* Register the I/O space with Linux */ if( check_region(host->io_port, 0xff) ) { printk("qla2100 : Failed to reserved i/o region 0x%04lx-0x%04lx already in use\n", host->io_port, host->io_port + 0xff); free_irq(host->irq, NULL); return 1; } request_region(host->io_port, 0xff, drvname); /* Initialized the timer */ START_TIMER(qla2100_timer,ha,WATCH_INTERVAL); return 0; } /************************************************************************** * qla2100_release * * Description: * Free the passed in Scsi_Host memory structures prior to unloading the * module. * * Input: * ha - pointer to host adapter structure * * Returns: * 0 - Always returns good status **************************************************************************/ int qla2100_release(struct Scsi_Host *host) { scsi_qla_host_t *ha = (scsi_qla_host_t *) host->hostdata; ENTER("qla2100_release"); /* if adpater is running and online */ if( !ha->flags.online ) return(0); /* turn-off interrupts on the card */ qla2100_disable_intrs(ha); /* Detach interrupts */ if( host->irq ) free_irq(host->irq, ha); /* release io space registers */ if( host->io_port ) release_region(host->io_port, 0xff); /* Disable timer */ if( ha->timer_active ) STOP_TIMER(qla2100_timer,ha) /* Kill the kernel thread for this host */ if( ha->dpc_handler != NULL ) { struct semaphore sem = MUTEX_LOCKED; ha->dpc_notify = &sem; send_sig(SIGKILL, ha->dpc_handler, 1); down(&sem); ha->dpc_notify = NULL; }#if USE_FLASH /* Move driver database to flash, if enabled. */ if( ha->flags.enable_flash_db_update && ha->flags.updated_fc_db ) { ha->flags.updated_fc_db = FALSE; qla2100_save_database(ha); }#endif#if MEMORY_MAPPED_IO if( ha->mmpbase ) { iounmap((void *) (((unsigned long) ha->mmpbase) & PAGE_MASK)); }#endif /* MEMORY_MAPPED_IO */ qla2100_mem_free(ha); ha->flags.online = FALSE; LEAVE("qla2100_release"); return(0); } /**************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -