qla_os.c
来自「linux2.6.16版本」· C语言 代码 · 共 2,593 行 · 第 1/5 页
C
2,593 行
list_for_each_safe(fcpl, fcptemp, &ha->fcports) { fcport = list_entry(fcpl, fc_port_t, list); /* fc ports */ list_del_init(&fcport->list); kfree(fcport); } INIT_LIST_HEAD(&ha->fcports); if (ha->fw_dump) free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order); vfree(ha->fw_dump24); vfree(ha->fw_dump_buffer); ha->fw_dump = NULL; ha->fw_dump24 = NULL; ha->fw_dumped = 0; ha->fw_dump_reading = 0; ha->fw_dump_buffer = NULL; vfree(ha->optrom_buffer);}/* * qla2x00_allocate_sp_pool * This routine is called during initialization to allocate * memory for local srb_t. * * Input: * ha = adapter block pointer. * * Context: * Kernel context. * * Note: Sets the ref_count for non Null sp to one. */static intqla2x00_allocate_sp_pool(scsi_qla_host_t *ha){ int rval; rval = QLA_SUCCESS; ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, mempool_free_slab, srb_cachep); if (ha->srb_mempool == NULL) { qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n"); rval = QLA_FUNCTION_FAILED; } return (rval);}/* * This routine frees all adapter allocated memory. * */static voidqla2x00_free_sp_pool( scsi_qla_host_t *ha){ if (ha->srb_mempool) { mempool_destroy(ha->srb_mempool); ha->srb_mempool = NULL; }}/*************************************************************************** qla2x00_do_dpc* This kernel thread is a task that is schedule by the interrupt handler* to perform the background processing for interrupts.** Notes:* This task always run in the context of a kernel thread. It* is kick-off by the driver's detect code and starts up* 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(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) qla2x00_update_fcports(ha); 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)); qla2x00_update_fcport(ha, fcport); } 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); if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags)) ha->isp_ops.beacon_blink(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))); } /* Check if beacon LED needs to be blinked */ if (ha->beacon_blink_led == 1) { set_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags); start_dpc++; } /* 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) || test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags) || start_dpc || test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || test_bit(BEACON_BLINK_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;}#if defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE)#define qla2x00_release_firmware() do { } while (0)#define qla2x00_pci_module_init() (0)#define qla2x00_pci_module_exit() do { } while (0)#else /* !defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE) *//* Firmware interface routines. */#define FW_BLOBS 6#define FW_ISP21XX 0#define FW_ISP22XX 1#define FW_ISP2300 2#define FW_ISP2322 3#define FW_ISP63XX 4#define FW_ISP24XX 5static DECLARE_MUTEX(qla_fw_lock);static struct fw_blob qla_fw_blobs[FW_BLOBS] = { { .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, }, { .name = "ql2200_fw.bin", .segs = { 0x1000, 0 }, }, { .name = "ql2300_fw.bin", .segs = { 0x800, 0 }, }, { .name = "ql2322_fw.bi
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?