📄 qla_os.c
字号:
* up one per adapter. It immediately goes to sleep and waits for* some fibre event. When either the interrupt handler or* the timer routine detects a event it will one of the task* bits then wake us up.**************************************************************************/static intqla2x00_do_dpc(void *data){ DECLARE_MUTEX_LOCKED(sem); scsi_qla_host_t *ha; fc_port_t *fcport; uint8_t status; uint16_t next_loopid; ha = (scsi_qla_host_t *)data; lock_kernel(); daemonize("%s_dpc", ha->host_str); allow_signal(SIGHUP); ha->dpc_wait = &sem; set_user_nice(current, -20); unlock_kernel(); complete(&ha->dpc_inited); while (1) { DEBUG3(printk("qla2x00: DPC handler sleeping\n")); if (down_interruptible(&sem)) break; if (ha->dpc_should_die) break; DEBUG3(printk("qla2x00: DPC handler waking up\n")); /* Initialization not yet finished. Don't do anything yet. */ if (!ha->flags.init_done || ha->dpc_active) continue; DEBUG3(printk("scsi(%ld): DPC handler\n", ha->host_no)); ha->dpc_active = 1; if (ha->flags.mbox_busy) { ha->dpc_active = 0; continue; } if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { DEBUG(printk("scsi(%ld): dpc: sched " "qla2x00_abort_isp ha = %p\n", ha->host_no, ha)); if (!(test_and_set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) { if (qla2x00_abort_isp(ha)) { /* failed. retry later */ set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); } DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n", ha->host_no)); } if (test_and_clear_bit(LOOP_RESET_NEEDED, &ha->dpc_flags)) { DEBUG(printk("scsi(%ld): dpc: sched loop_reset()\n", ha->host_no)); qla2x00_loop_reset(ha); } if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) && (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) { DEBUG(printk("scsi(%ld): qla2x00_reset_marker()\n", ha->host_no)); qla2x00_rst_aen(ha); clear_bit(RESET_ACTIVE, &ha->dpc_flags); } /* Retry each device up to login retry count */ if ((test_and_clear_bit(RELOGIN_NEEDED, &ha->dpc_flags)) && !test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) && atomic_read(&ha->loop_state) != LOOP_DOWN) { DEBUG(printk("scsi(%ld): qla2x00_port_login()\n", ha->host_no)); next_loopid = 0; list_for_each_entry(fcport, &ha->fcports, list) { if (fcport->port_type != FCT_TARGET) continue; /* * If the port is not ONLINE then try to login * to it if we haven't run out of retries. */ if (atomic_read(&fcport->state) != FCS_ONLINE && fcport->login_retry) { fcport->login_retry--; if (fcport->flags & FCF_FABRIC_DEVICE) { if (fcport->flags & FCF_TAPE_PRESENT) ha->isp_ops.fabric_logout( ha, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); status = qla2x00_fabric_login( ha, fcport, &next_loopid); } else status = qla2x00_local_device_login( ha, fcport->loop_id); if (status == QLA_SUCCESS) { fcport->old_loop_id = fcport->loop_id; DEBUG(printk("scsi(%ld): port login OK: logged in ID 0x%x\n", ha->host_no, fcport->loop_id)); fcport->port_login_retry_count = ha->port_down_retry_count * PORT_RETRY_TIME; atomic_set(&fcport->state, FCS_ONLINE); atomic_set(&fcport->port_down_timer, ha->port_down_retry_count * PORT_RETRY_TIME); fcport->login_retry = 0; } else if (status == 1) { set_bit(RELOGIN_NEEDED, &ha->dpc_flags); /* retry the login again */ DEBUG(printk("scsi(%ld): Retrying %d login again loop_id 0x%x\n", ha->host_no, fcport->login_retry, fcport->loop_id)); } else { fcport->login_retry = 0; } } if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) break; } DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n", ha->host_no)); } if ((test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags)) && atomic_read(&ha->loop_state) != LOOP_DOWN) { clear_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags); DEBUG(printk("scsi(%ld): qla2x00_login_retry()\n", ha->host_no)); set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); DEBUG(printk("scsi(%ld): qla2x00_login_retry - end\n", ha->host_no)); } if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n", ha->host_no)); if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags))) { qla2x00_loop_resync(ha); clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags); } DEBUG(printk("scsi(%ld): qla2x00_loop_resync - end\n", ha->host_no)); } if (test_and_clear_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags)) { DEBUG(printk("scsi(%ld): Rescan flagged fcports...\n", ha->host_no)); qla2x00_rescan_fcports(ha); DEBUG(printk("scsi(%ld): Rescan flagged fcports..." "end.\n", ha->host_no)); } if (!ha->interrupts_on) ha->isp_ops.enable_intrs(ha); ha->dpc_active = 0; } /* End of while(1) */ DEBUG(printk("scsi(%ld): DPC handler exiting\n", ha->host_no)); /* * Make sure that nobody tries to wake us up again. */ ha->dpc_wait = NULL; ha->dpc_active = 0; complete_and_exit(&ha->dpc_exited, 0);}/** qla2x00_rst_aen* Processes asynchronous reset.** Input:* ha = adapter block pointer.*/static voidqla2x00_rst_aen(scsi_qla_host_t *ha){ if (ha->flags.online && !ha->flags.reset_active && !atomic_read(&ha->loop_down_timer) && !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) { do { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); /* * Issue marker command only when we are going to start * the I/O. */ ha->marker_needed = 1; } while (!atomic_read(&ha->loop_down_timer) && (test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags))); }}static voidqla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp){ struct scsi_cmnd *cmd = sp->cmd; if (sp->flags & SRB_DMA_VALID) { if (cmd->use_sg) { dma_unmap_sg(&ha->pdev->dev, cmd->request_buffer, cmd->use_sg, cmd->sc_data_direction); } else if (cmd->request_bufflen) { dma_unmap_single(&ha->pdev->dev, sp->dma_handle, cmd->request_bufflen, cmd->sc_data_direction); } sp->flags &= ~SRB_DMA_VALID; } CMD_SP(cmd) = NULL;}voidqla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp){ struct scsi_cmnd *cmd = sp->cmd; qla2x00_sp_free_dma(ha, sp); mempool_free(sp, ha->srb_mempool); cmd->scsi_done(cmd);}/*************************************************************************** qla2x00_timer** Description:* One second timer** Context: Interrupt***************************************************************************/static voidqla2x00_timer(scsi_qla_host_t *ha){ unsigned long cpu_flags = 0; fc_port_t *fcport; int start_dpc = 0; int index; srb_t *sp; int t; /* * Ports - Port down timer. * * Whenever, a port is in the LOST state we start decrementing its port * down timer every second until it reaches zero. Once it reaches zero * the port it marked DEAD. */ t = 0; list_for_each_entry(fcport, &ha->fcports, list) { if (fcport->port_type != FCT_TARGET) continue; if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) { if (atomic_read(&fcport->port_down_timer) == 0) continue; if (atomic_dec_and_test(&fcport->port_down_timer) != 0) atomic_set(&fcport->state, FCS_DEVICE_DEAD); DEBUG(printk("scsi(%ld): fcport-%d - port retry count: " "%d remaining\n", ha->host_no, t, atomic_read(&fcport->port_down_timer))); } t++; } /* End of for fcport */ /* Loop down handler. */ if (atomic_read(&ha->loop_down_timer) > 0 && !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) && ha->flags.online) { if (atomic_read(&ha->loop_down_timer) == ha->loop_down_abort_time) { DEBUG(printk("scsi(%ld): Loop Down - aborting the " "queues before time expire\n", ha->host_no)); if (!IS_QLA2100(ha) && ha->link_down_timeout) atomic_set(&ha->loop_state, LOOP_DEAD); /* Schedule an ISP abort to return any tape commands. */ spin_lock_irqsave(&ha->hardware_lock, cpu_flags); for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { fc_port_t *sfcp; sp = ha->outstanding_cmds[index]; if (!sp) continue; sfcp = sp->fcport; if (!(sfcp->flags & FCF_TAPE_PRESENT)) continue; set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; } spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags); start_dpc++; } /* if the loop has been down for 4 minutes, reinit adapter */ if (atomic_dec_and_test(&ha->loop_down_timer) != 0) { DEBUG(printk("scsi(%ld): Loop down exceed 4 mins - " "restarting queues.\n", ha->host_no)); set_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags); start_dpc++; if (!(ha->device_flags & DFLG_NO_CABLE)) { DEBUG(printk("scsi(%ld): Loop down - " "aborting ISP.\n", ha->host_no)); qla_printk(KERN_WARNING, ha, "Loop down - aborting ISP.\n"); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); } } DEBUG3(printk("scsi(%ld): Loop Down - seconds remaining %d\n", ha->host_no, atomic_read(&ha->loop_down_timer))); } /* Schedule the DPC routine if needed */ if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || test_bit(LOOP_RESET_NEEDED, &ha->dpc_flags) || start_dpc || test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || test_bit(RELOGIN_NEEDED, &ha->dpc_flags)) && ha->dpc_wait && !ha->dpc_active) { up(ha->dpc_wait); } qla2x00_restart_timer(ha, WATCH_INTERVAL);}/* XXX(hch): crude hack to emulate a down_timeout() */intqla2x00_down_timeout(struct semaphore *sema, unsigned long timeout){ const unsigned int step = 100; /* msecs */ unsigned int iterations = jiffies_to_msecs(timeout)/100; do { if (!down_trylock(sema)) return 0; if (msleep_interruptible(step)) break; } while (--iterations >= 0); return -ETIMEDOUT;}static struct qla_board_info qla_board_tbl[] = { { .drv_name = "qla2400", .isp_name = "ISP2422", .fw_fname = "ql2400_fw.bin", .sht = &qla24xx_driver_template, }, { .drv_name = "qla2400", .isp_name = "ISP2432", .fw_fname = "ql2400_fw.bin", .sht = &qla24xx_driver_template, },};static struct pci_device_id qla2xxx_pci_tbl[] = { { .vendor = PCI_VENDOR_ID_QLOGIC, .device = PCI_DEVICE_ID_QLOGIC_ISP2422, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = (unsigned long)&qla_board_tbl[0], }, { .vendor = PCI_VENDOR_ID_QLOGIC, .device = PCI_DEVICE_ID_QLOGIC_ISP2432, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = (unsigned long)&qla_board_tbl[1], }, {0, 0},};MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);static int __devinitqla2xxx_probe_one(struct pci_dev *pdev, const struct pci_device_id *id){ return qla2x00_probe_one(pdev, (struct qla_board_info *)id->driver_data);}static void __devexitqla2xxx_remove_one(struct pci_dev *pdev){ qla2x00_remove_one(pdev);}static struct pci_driver qla2xxx_pci_driver = { .name = "qla2xxx", .id_table = qla2xxx_pci_tbl, .probe = qla2xxx_probe_one, .remove = __devexit_p(qla2xxx_remove_one),};/** * qla2x00_module_init - Module initialization. **/static int __initqla2x00_module_init(void){ int ret = 0; /* Allocate cache for SRBs. */ srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (srb_cachep == NULL) { printk(KERN_ERR "qla2xxx: Unable to allocate SRB cache...Failing load!\n"); return -ENOMEM; } /* Derive version string. */ strcpy(qla2x00_version_str, QLA2XXX_VERSION);#if DEBUG_QLA2100 strcat(qla2x00_version_str, "-debug");#endif qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) return -ENODEV; printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n"); ret = pci_module_init(&qla2xxx_pci_driver); if (ret) { kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); } return ret;}/** * qla2x00_module_exit - Module cleanup. **/static void __exitqla2x00_module_exit(void){ pci_unregister_driver(&qla2xxx_pci_driver); kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template);}module_init(qla2x00_module_init);module_exit(qla2x00_module_exit);MODULE_AUTHOR("QLogic Corporation");MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver");MODULE_LICENSE("GPL");MODULE_VERSION(QLA2XXX_VERSION);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -