qla_mbx.c
来自「这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自」· C语言 代码 · 共 2,536 行 · 第 1/4 页
C
2,536 行
/* * QLOGIC LINUX SOFTWARE * * QLogic ISP2x00 device driver for Linux 2.4.x * Copyright (C) 2002 Qlogic Corporation * (www.qlogic.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * */#include "qla_mbx.h"/* * Local Function Prototypes. */STATIC uint8_tqla2x00_mailbox_command(scsi_qla_host_t *, mbx_cmd_t *);STATIC voidqla2x00_mbx_sem_timeout(unsigned long);STATIC uint8_tqla2x00_get_mbx_access(scsi_qla_host_t *, uint32_t);STATIC uint8_tqla2x00_release_mbx_access(scsi_qla_host_t *, uint32_t);STATIC uint8_tqla2x00_mbx_q_add(scsi_qla_host_t *, mbx_cmdq_t **);STATIC voidqla2x00_mbx_q_get(scsi_qla_host_t *, mbx_cmdq_t **);STATIC voidqla2x00_mbx_q_memb_alloc(scsi_qla_host_t *, mbx_cmdq_t **);STATIC voidqla2x00_mbx_q_memb_free(scsi_qla_host_t *, mbx_cmdq_t *);STATIC intqla2x00_load_ram(scsi_qla_host_t *, uint32_t, uint32_t, uint16_t);STATIC intqla2x00_execute_fw(scsi_qla_host_t *);#if defined(WORD_FW_LOAD)STATIC intqla2x00_write_ram_word(scsi_qla_host_t *, uint16_t, uint16_t);STATIC intqla2x00_read_ram_word(scsi_qla_host_t *, uint16_t, uint16_t *);#endifSTATIC intqla2x00_mbx_reg_test(scsi_qla_host_t *);STATIC intqla2x00_verify_checksum(scsi_qla_host_t *);STATIC intqla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t);STATIC intqla2x00_abort_command(scsi_qla_host_t *, srb_t *);STATIC intqla2x00_abort_device(scsi_qla_host_t *, uint16_t, uint16_t);#if USE_ABORT_TGTSTATIC intqla2x00_abort_target(fc_port_t *fcport);#endifSTATIC intqla2x00_target_reset(scsi_qla_host_t *, uint16_t, uint16_t);STATIC intqla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, uint8_t *, uint16_t *);STATIC intqla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *);#if defined(INTAPI)intqla2x00_loopback_test(scsi_qla_host_t *, INT_LOOPBACK_REQ *, uint16_t *);#endifSTATIC intqla2x00_init_firmware(scsi_qla_host_t *, uint16_t);STATIC intqla2x00_get_port_database(scsi_qla_host_t *, fcdev_t *, uint8_t);STATIC intqla2x00_get_firmware_state(scsi_qla_host_t *, uint16_t *);STATIC intqla2x00_get_port_name(scsi_qla_host_t *, uint16_t, uint8_t *, uint8_t);STATIC uint8_tqla2x00_get_link_status(scsi_qla_host_t *, uint8_t, void *, uint16_t *);STATIC intqla2x00_lip_reset(scsi_qla_host_t *);STATIC intqla2x00_send_sns(scsi_qla_host_t *, dma_addr_t, uint16_t, size_t);STATIC intqla2x00_login_fabric(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t, uint16_t *, uint8_t);STATIC intqla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id);STATIC intqla2x00_full_login_lip(scsi_qla_host_t *ha);STATIC intqla2x00_get_port_list(scsi_qla_host_t *, port_list_entry_t *, dma_addr_t, uint16_t, uint16_t *);#if 0 /* not yet needed */STATIC intqla2x00_dump_ram(scsi_qla_host_t *, uint32_t, dma_addr_t, uint32_t);#endif#if MPIO_SUPPORTSTATIC intqla2x00_lun_reset(scsi_qla_host_t *, uint16_t, uint16_t);#endifSTATIC intqla2x00_send_rnid_mbx(scsi_qla_host_t *, uint16_t, uint8_t, dma_addr_t, size_t, uint16_t *);STATIC intqla2x00_set_rnid_params_mbx(scsi_qla_host_t *, dma_addr_t, size_t, uint16_t *);STATIC intqla2x00_get_rnid_params_mbx(scsi_qla_host_t *, dma_addr_t, size_t, uint16_t *);/***************************//* Function implementation *//***************************/STATIC voidqla2x00_mbx_sem_timeout(unsigned long data){ struct semaphore *sem_ptr = (struct semaphore *)data; DEBUG11(printk("qla2x00_sem_timeout: entered.\n");) if (sem_ptr != NULL) { up(sem_ptr); } DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n");)}/* * tov = timeout value in seconds */STATIC uint8_tqla2x00_get_mbx_access(scsi_qla_host_t *ha, uint32_t tov){ uint8_t ret; int prev_val = 1; /* assume no access yet */ mbx_cmdq_t *ptmp_mbq; struct timer_list tmp_cmd_timer; unsigned long cpu_flags; DEBUG11(printk("qla2x00_get_mbx_access(%ld): entered.\n", ha->host_no);) while (1) { if (test_bit(MBX_CMD_WANT, (void *)&(ha->mbx_cmd_flags)) == 0) { DEBUG11(printk("qla2x00_get_mbx_access(%ld): going " " to test access flags.\n", ha->host_no);) /* No one else is waiting. Go ahead and try to * get access. */ if ((prev_val = test_and_set_bit(MBX_CMD_ACTIVE, (void *)&ha->mbx_cmd_flags)) == 0) { break; } } /* wait for previous command to finish */ DEBUG(printk("qla2x00_get_mbx_access(%ld): access " "flags=%x. busy. Waiting for access. curr time=0x%lx.\n", ha->host_no, ha->mbx_cmd_flags, jiffies);) DEBUG11(printk("qla2x00_get_mbx_access(%ld): access " "flags=%x. busy. Waiting for access. curr time=0x%lx.\n", ha->host_no, ha->mbx_cmd_flags, jiffies);) /* * Init timer and get semaphore from mbx q. After we got valid * semaphore pointer the MBX_CMD_WANT flag would also had * been set. */ qla2x00_mbx_q_add(ha, &ptmp_mbq); if (ptmp_mbq == NULL) { /* queue full? problem? can't proceed. */ DEBUG2_3_11(printk("qla2x00_get_mbx_access(%ld): ERROR " "no more mbx_q allowed. exiting.\n", ha->host_no);) break; } /* init timer and semaphore */ init_timer(&tmp_cmd_timer); tmp_cmd_timer.data = (unsigned long)&ptmp_mbq->cmd_sem; tmp_cmd_timer.function = (void (*)(unsigned long))qla2x00_mbx_sem_timeout; tmp_cmd_timer.expires = jiffies + tov * HZ; DEBUG11(printk("get_mbx_access(%ld): adding timer. " "curr time=0x%lx timeoutval=0x%lx.\n", ha->host_no, jiffies, tmp_cmd_timer.expires);) /* wait. *//* add_timer(&tmp_cmd_timer);*/ DEBUG11(printk("get_mbx_access(%ld): going to sleep. " "current time=0x%lx.\n", ha->host_no, jiffies);) down_interruptible(&ptmp_mbq->cmd_sem); DEBUG11(printk("get_mbx_access(%ld): woke up. current " "time=0x%lx.\n", ha->host_no, jiffies);)/* del_timer(&tmp_cmd_timer);*/ /* try to get lock again. we'll test later to see * if we actually got the lock. */ prev_val = test_and_set_bit(MBX_CMD_ACTIVE, (void *)&(ha->mbx_cmd_flags)); /* * After we tried to get access then we check to see * if we need to clear the MBX_CMD_WANT flag. Don't clear * this flag before trying to get access or else another * new thread might grab it before we did. */ spin_lock_irqsave(&ha->mbx_q_lock, cpu_flags); if (ha->mbx_q_head == NULL) { /* We're the last thread in queue. */ clear_bit(MBX_CMD_WANT, (void *)&ha->mbx_cmd_flags); } qla2x00_mbx_q_memb_free(ha, ptmp_mbq); spin_unlock_irqrestore(&ha->mbx_q_lock, cpu_flags); break; } if (prev_val == 0) { /* We got the lock */ DEBUG11(printk("qla2x00_get_mbx_access(%ld): success.\n", ha->host_no);) ret = QL_STATUS_SUCCESS; } else { /* Timeout or resource error. */ DEBUG2_3_11(printk("qla2x00_get_mbx_access(%ld): timed out.\n", ha->host_no);) ret = QL_STATUS_TIMEOUT; } return ret;}STATIC uint8_tqla2x00_release_mbx_access(scsi_qla_host_t *ha, uint32_t tov){ mbx_cmdq_t *next_thread; DEBUG11(printk("qla2x00_release_mbx_access:(%ld): entered.\n", ha->host_no);) clear_bit(MBX_CMD_ACTIVE, (void *)&(ha->mbx_cmd_flags)); /* Wake up one pending mailbox cmd thread in queue. */ qla2x00_mbx_q_get(ha, &next_thread); if (next_thread) { DEBUG11(printk("qla2x00_release_mbx_access: found pending " "mbx cmd. Waking up sem in %p.\n", &next_thread);) up(&next_thread->cmd_sem); } DEBUG11(printk("qla2x00_release_mbx_access:(%ld): exiting.\n", ha->host_no);) return QL_STATUS_SUCCESS;}/* Allocates a mbx_cmdq_t struct and add to the mbx_q list. */STATIC uint8_tqla2x00_mbx_q_add(scsi_qla_host_t *ha, mbx_cmdq_t **ret_mbq){ uint8_t ret; unsigned long cpu_flags; mbx_cmdq_t *ptmp = NULL; spin_lock_irqsave(&ha->mbx_q_lock, cpu_flags); DEBUG11(printk("qla2x00_mbx_q_add: got mbx_q spinlock. " "Inst=%d.\n", apiHBAInstance);) qla2x00_mbx_q_memb_alloc(ha, &ptmp); if (ptmp == NULL) { /* can't add any more threads */ DEBUG2_3_11(printk("qla2x00_mbx_q_add: ERROR no more " "ioctl threads allowed. Inst=%d.\n", apiHBAInstance);) ret = QL_STATUS_RESOURCE_ERROR; } else { if (ha->mbx_q_tail == NULL) { /* First thread to queue. */ set_bit(IOCTL_WANT, (void *)&ha->mbx_cmd_flags); ha->mbx_q_head = ptmp; } else { ha->mbx_q_tail->pnext = ptmp; } ha->mbx_q_tail = ptmp; *ret_mbq = ptmp; /* Now init the semaphore */ init_MUTEX_LOCKED(&ptmp->cmd_sem); ret = QL_STATUS_SUCCESS; } DEBUG11(printk("qla2x00_mbx_q_add: going to release spinlock. " "ret_mbq=%p, ret=%d. Inst=%d.\n", *ret_mbq, ret, apiHBAInstance);) spin_unlock_irqrestore(&ha->mbx_q_lock, cpu_flags); return ret;}/* Just remove and return first member from mbx_cmdq. Don't free anything. */STATIC voidqla2x00_mbx_q_get(scsi_qla_host_t *ha, mbx_cmdq_t **ret_mbq){ unsigned long cpu_flags; spin_lock_irqsave(&ha->mbx_q_lock, cpu_flags); DEBUG11(printk("qla2x00_mbx_q_get: got mbx_q spinlock. " "Inst=%d.\n", apiHBAInstance);) /* Remove from head */ *ret_mbq = ha->mbx_q_head; if (ha->mbx_q_head != NULL) { ha->mbx_q_head = ha->mbx_q_head->pnext; if (ha->mbx_q_head == NULL) { /* That's the last one in queue. */ ha->mbx_q_tail = NULL; } (*ret_mbq)->pnext = NULL; } DEBUG11(printk("qla2x00_mbx_q_remove: return ret_mbq=%p. Going to " "release spinlock. Inst=%d.\n", *ret_mbq, apiHBAInstance);) spin_unlock_irqrestore(&ha->mbx_q_lock, cpu_flags);}/* Find a free mbx_q member from the array. Must already got the * mbx_q_lock spinlock. */STATIC voidqla2x00_mbx_q_memb_alloc(scsi_qla_host_t *ha, mbx_cmdq_t **ret_mbx_q_memb){ mbx_cmdq_t *ptmp = NULL; DEBUG11(printk("qla2x00_mbx_q_memb_alloc: entered. " "Inst=%d.\n", apiHBAInstance);) ptmp = ha->mbx_sem_pool_head; if (ptmp != NULL) { ha->mbx_sem_pool_head = ptmp->pnext; ptmp->pnext = NULL; if (ha->mbx_sem_pool_head == NULL) { ha->mbx_sem_pool_tail = NULL; } } else { /* We ran out of pre-allocated semaphores. Try to allocate * a new one. */ ptmp = (void *)KMEM_ZALLOC(sizeof(mbx_cmdq_t), 40); } *ret_mbx_q_memb = ptmp; DEBUG11(printk("qla2x00_mbx_q_memb_alloc: return waitq_memb=%p. " "Inst=%d.\n", *ret_mbx_q_memb, apiHBAInstance);)}/* Add the specified mbx_q member back to the free semaphore pool. Must * already got the mbx_q_lock spinlock. */STATIC voidqla2x00_mbx_q_memb_free(scsi_qla_host_t *ha, mbx_cmdq_t *pfree_mbx_q_memb){ DEBUG11(printk("qla2x00_mbx_q_memb_free: entered. Inst=%d.\n", apiHBAInstance);) if (pfree_mbx_q_memb != NULL) { if (ha->mbx_sem_pool_tail != NULL) { /* Add to tail */ ha->mbx_sem_pool_tail->pnext = pfree_mbx_q_memb; } else { ha->mbx_sem_pool_head = pfree_mbx_q_memb; } ha->mbx_sem_pool_tail = pfree_mbx_q_memb; } /* put it back to the free pool. */ DEBUG11(printk("qla2x00_mbx_q_memb_free: exiting. " "Inst=%d.\n", apiHBAInstance);)}/* * qla2x00_mailbox_command * Issue mailbox command and waits for completion. * * Input: * ha = adapter block pointer. * mcp = driver internal mbx struct pointer. * * Output: * mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data. * * Returns: * 0 : QL_STATUS_SUCCESS = cmd performed success * 1 : QL_STATUS_ERROR (error encountered) * 6 : QL_STATUS_TIMEOUT (timeout condition encountered) * * Context: * Kernel context. */STATIC uint8_tqla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp){ unsigned long flags = 0; device_reg_t *reg = ha->iobase; struct timer_list tmp_intr_timer; uint8_t abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); uint8_t discard; uint8_t io_lock_on = ha->init_done; uint8_t mbx_count; uint8_t status = 0; uint8_t tmp_stat = 0; uint16_t command; uint16_t *iptr, *optr; uint16_t data; uint32_t cnt; uint32_t mboxes; unsigned long mbx_flags = 0; DEBUG11(printk("qla2x00_mailbox_command(%ld): entered.\n", ha->host_no);) /* * Wait for active mailbox commands to finish by waiting at most * tov seconds. This is to serialize actual issuing of mailbox cmds * during non ISP abort time. */ if (!abort_active) { tmp_stat = qla2x00_get_mbx_access(ha, mcp->tov); if (tmp_stat != QL_STATUS_SUCCESS) { /* Timeout occurred. Return error. */ DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): cmd " "access timeout. Exiting.\n", ha->host_no);) return QL_STATUS_TIMEOUT; } } ha->flags.mbox_busy = TRUE; /* Save mailbox command for debug */ ha->mcp = mcp; /* Try to get mailbox register access */ if (!abort_active) QLA_MBX_REG_LOCK(ha); DEBUG11(printk("scsi%d: prepare to issue mbox cmd=0x%x.\n", (int)ha->host_no, mcp->mb[0]);) ha->mbox_trace = 0; spin_lock_irqsave(&ha->hardware_lock, flags); /* Load mailbox registers. */ optr = (uint16_t *)®->mailbox0; mbx_count = MAILBOX_REGISTER_COUNT; iptr = mcp->mb; command = mcp->mb[0]; mboxes = mcp->out_mb; for (cnt = 0; cnt < mbx_count; cnt++) {#if defined(ISP2200) if (cnt == 8) { optr = (uint16_t *)®->mailbox8; }#endif if (mboxes & BIT_0) { WRT_REG_WORD(optr, *iptr); } mboxes >>= 1; optr++; iptr++; }#if defined(QL_DEBUG_LEVEL_1) printk("qla2x00_mailbox_command: Loaded MBX registers " "(displayed in bytes) = \n"); qla2x00_dump_buffer((uint8_t *)mcp->mb, 16); printk("\n"); qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x10), 16); printk("\n"); qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x20), 8); printk("\n"); printk("qla2x00_mailbox_command: I/O address = %lx.\n", (u_long)optr); qla2x00_dump_regs(ha->host);#endif /* Issue set host interrupt command to send cmd out. */ ha->flags.mbox_int = FALSE; clear_bit(MBX_INTERRUPT, (void *)&(ha->mbx_cmd_flags)); /* Unlock mbx registers and wait for interrupt */ DEBUG11(printk("qla2x00_mailbox_command: going to unlock irq & " "waiting for interrupt. jiffies=%lx.\n", jiffies);) /* Wait for mbx cmd completion until timeout */ if (!abort_active && io_lock_on) { /* sleep on completion semaphore */ if (!test_bit(MBX_INTERRUPT, (void *)&ha->mbx_cmd_flags) && !(test_bit(ISP_RESET_NEEDED, &ha->dpc_flags))) { DEBUG11(printk("qla2x00_mailbox_command(%ld): " "INTERRUPT MODE. Initializing timer.\n", ha->host_no);) init_timer(&tmp_intr_timer); tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem; tmp_intr_timer.expires = jiffies + mcp->tov * HZ; tmp_intr_timer.function = (void (*)(unsigned long))qla2x00_mbx_sem_timeout; DEBUG11(printk("qla2x00_mailbox_command(%ld): " "Adding timer.\n", ha->host_no);) add_timer(&tmp_intr_timer); DEBUG11(printk("qla2x00_mailbox_command: going to " "unlock & sleep. time=0x%lx.\n", jiffies);) MBOX_TRACE(ha,BIT_0); set_bit(MBX_INTR_WAIT, (void *)&(ha->mbx_cmd_flags)); WRT_REG_WORD(®->host_cmd, HC_SET_HOST_INT); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (!abort_active) QLA_MBX_REG_UNLOCK(ha); MBOX_TRACE(ha,BIT_1); /* Wait for either the timer to expire * or the mbox completion interrupt */ down_interruptible(&ha->mbx_intr_sem); DEBUG11(printk("qla2x00_mailbox_command:" "waking up." "time=0x%lx\n", jiffies);) clear_bit(MBX_INTR_WAIT, (void *)&(ha->mbx_cmd_flags)); /* delete the timer */ del_timer(&tmp_intr_timer); }#if QLA2100_LIPTEST if( mbxtimeout ) { DEBUG(printk("qla2x00_mailbox_command(%ld): " "INTERRUPT MODE - testing timeout handling.\n", ha->host_no);) ha->flags.mbox_int= FALSE; } mbxtimeout= 0;#endif } else { DEBUG3_11(printk("qla2x00_mailbox_command(%ld): cmd=%x " "POLLING MODE.\n", ha->host_no, command);) WRT_REG_WORD(®->host_cmd, HC_SET_HOST_INT); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (!abort_active) QLA_MBX_REG_UNLOCK(ha); cnt = jiffies + mcp->tov * HZ; /* wait at most tov secs */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?