qla_ip.c
来自「这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自」· C语言 代码 · 共 1,757 行 · 第 1/4 页
C
1,757 行
/****************************************************************************** * 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. * ******************************************************************************//**************************************************************************** Please see revision.notes for revision history.*****************************************************************************/static __u8 hwbroadcast_addr[ETH_ALEN] = { [0 ... ETH_ALEN-1] = 0xFF };/** * qla2x00_ip_initialize() - Initialize RISC IP support. * @ha: SCSI driver HA context * * Prior to RISC IP initialization, this routine, if necessary, will reset all * buffers in the receive buffer ring. * * Returns TRUE if the RISC IP initialization succeeds. */static intqla2x00_ip_initialize(scsi_qla_host_t *ha){ int i; int status; unsigned long flags; device_reg_t *reg; static mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; struct ip_init_cb *ipinit_cb; dma_addr_t ipinit_cb_dma; DEBUG12(printk("%s: enter\n", __func__);) status = FALSE; /* Initialize IP data in ha */ ha->ipdev_db_top = NULL; ha->ipdev_db_bottom = NULL; ha->ipdev_db_next_free = &ha->ipdev_db[0]; for (i = 0; i < QLLAN_MAX_IP_DEVICES; i++) { ha->ipdev_db[i].index = i; ha->ipdev_db[i].next = &ha->ipdev_db[i+1]; } ha->ipdev_db[QLLAN_MAX_IP_DEVICES-1].next = NULL; /* Reset/pack buffers owned by RISC in receive buffer ring */ if (ha->rec_entries_in != ha->rec_entries_out) { struct buffer_cb *bcb; uint16_t rec_out; struct risc_rec_entry *rec_entry; bcb = ha->receive_buffers; rec_out = ha->rec_entries_out; /* * Must locate all RISC owned buffers and pack them in the * buffer ring. */ /* between IpBufferOut and IpBufferIN */ for (i = 0; i < ha->max_receive_buffers; i++, bcb++) { if (test_bit(BCB_RISC_OWNS_BUFFER, &bcb->state)) { /* * Set RISC owned buffer into receive buffer * ring. */ rec_entry = &ha->risc_rec_q[rec_out]; rec_entry->handle = bcb->handle; rec_entry->data_addr_low = LS_64BITS(bcb->skb_data_dma); rec_entry->data_addr_high = MS_64BITS(bcb->skb_data_dma); if (rec_out < IP_BUFFER_QUEUE_DEPTH - 1) rec_out++; else rec_out = 0; } } /* Verify correct number of RISC owned buffers were found */ if (rec_out != ha->rec_entries_in) { /* Incorrect number of RISC owned buffers?? */ DEBUG12(printk("%s: incorrect number of RISC " "owned buffers, disable IP\n", __func__);) ha->flags.enable_ip = FALSE; return (FALSE); } } /* Init RISC buffer pointer */ spin_lock_irqsave(&ha->hardware_lock, flags); reg = ha->iobase; WRT_REG_WORD(®->mailbox8, ha->rec_entries_in); spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for a ready state from the adapter */ while (!ha->init_done || ha->dpc_active) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } /* Setup IP initialization control block */ ipinit_cb = pci_alloc_consistent(ha->pdev, sizeof(struct ip_init_cb), &ipinit_cb_dma); if (ipinit_cb) { memset(ipinit_cb, 0, sizeof(struct ip_init_cb)); ipinit_cb->version = IPICB_VERSION; ipinit_cb->firmware_options = IPICB_OPTION_NO_BROADCAST_FASTPOST | IPICB_OPTION_64BIT_ADDRESSING; ipinit_cb->header_size = ha->header_size; ipinit_cb->mtu = (uint16_t)ha->mtu; ipinit_cb->receive_buffer_size = (uint16_t)ha->receive_buff_data_size; ipinit_cb->receive_queue_size = IP_BUFFER_QUEUE_DEPTH; ipinit_cb->low_water_mark = IPICB_LOW_WATER_MARK; ipinit_cb->receive_queue_addr[0] = LSW(ha->risc_rec_q_dma); ipinit_cb->receive_queue_addr[1] = MSW(ha->risc_rec_q_dma); ipinit_cb->receive_queue_addr[2] = QL21_64BITS_3RDWD(ha->risc_rec_q_dma); ipinit_cb->receive_queue_addr[3] = QL21_64BITS_4THWD(ha->risc_rec_q_dma); ipinit_cb->receive_queue_in = ha->rec_entries_out; ipinit_cb->fast_post_count = IPICB_FAST_POST_COUNT; ipinit_cb->container_count = IPICB_BUFFER_CONTAINER_COUNT; ipinit_cb->resource_allocation = IPICB_IOCB_RESERVE_COUNT; /* Issue mailbox command to initialize IP firmware */ mcp->mb[0] = MBC_INITIALIZE_IP; mcp->mb[2] = MSW(ipinit_cb_dma); mcp->mb[3] = LSW(ipinit_cb_dma); mcp->mb[6] = QL21_64BITS_4THWD(ipinit_cb_dma); mcp->mb[7] = QL21_64BITS_3RDWD(ipinit_cb_dma); mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; mcp->in_mb = MBX_0; mcp->tov = 30; mcp->buf_size = sizeof(struct ip_init_cb); mcp->flags = MBX_DMA_OUT; status = qla2x00_mailbox_command(ha, mcp); if (status == QL_STATUS_SUCCESS) { /* IP initialization successful */ DEBUG12(printk("%s: successful\n", __func__);) ha->flags.enable_ip = TRUE; /* Force database update */ set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); /* qla2x00_loop_resync(ha); */ if (ha->dpc_wait && !ha->dpc_active) { up(ha->dpc_wait); } status = TRUE; } else { DEBUG12(printk("%s: MBC_INITIALIZE_IP " "failed %x MB0 %x\n", __func__, status, mcp->mb[0]);) status = FALSE; } pci_free_consistent(ha->pdev, sizeof(struct ip_init_cb), ipinit_cb, ipinit_cb_dma); } else { DEBUG12(printk("%s: memory allocation error\n", __func__);) } return (status);}/** * qla2x00_ip_send_complete() - Handle IP send completion. * @ha: SCSI driver HA context * @handle: handle to completed send_cb * @comp_status: Firmware completion status of send_cb * * Upon cleanup of the internal active-scb queue, the IP driver is notified of * the completion. */static voidqla2x00_ip_send_complete(scsi_qla_host_t *ha, uint32_t handle, uint16_t comp_status){ struct send_cb *scb; /* Set packet pointer from queue entry handle */ if (handle < MAX_SEND_PACKETS) { scb = ha->active_scb_q[handle]; if (scb) { ha->ipreq_cnt--; ha->active_scb_q[handle] = NULL; scb->comp_status = comp_status; pci_unmap_single(ha->pdev, scb->skb_data_dma, scb->skb->len, PCI_DMA_TODEVICE); /* Return send packet to IP driver */ (*ha->send_completion_routine)(scb); return; } } /* Invalid handle from RISC, reset RISC firmware */ printk(KERN_WARNING "%s: Bad IP send handle %x - aborting ISP\n", __func__, handle); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);}/** * qla2x00_ip_receive() - Handle IP receive IOCB. * @ha: SCSI driver HA context * @pkt: RISC IP receive packet * * Upon preparation of one or more buffer_cbs, the IP driver is notified of * the received packet. */static voidqla2x00_ip_receive(scsi_qla_host_t *ha, response_t *pkt){ uint32_t handle; uint32_t packet_size; uint16_t linked_bcb_cnt; uint32_t rec_data_size; struct buffer_cb *bcb; struct buffer_cb *nbcb; struct ip_rec_entry *iprec_entry; DEBUG12(printk("%s: enter\n", __func__);) iprec_entry = (struct ip_rec_entry *)pkt; /* If split buffer, set header size for 1st buffer */ if (iprec_entry->comp_status & IPREC_STATUS_SPLIT_BUFFER) rec_data_size = ha->header_size; else rec_data_size = ha->receive_buff_data_size; handle = iprec_entry->buffer_handles[0]; if (handle >= ha->max_receive_buffers) { /* Invalid handle from RISC, reset RISC firmware */ printk(KERN_WARNING "%s: Bad IP buffer handle %x (> buffer_count)...Post " "ISP Abort\n", __func__, handle); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); return; } bcb = &ha->receive_buffers[handle]; if (!test_and_clear_bit(BCB_RISC_OWNS_BUFFER, &bcb->state)) { /* Invalid handle from RISC, reset RISC firmware */ printk(KERN_WARNING "%s: Bad IP buffer handle %x (!RISC_owned)...Post " "ISP Abort\n", __func__, handle); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); return; } packet_size = iprec_entry->sequence_length; bcb->comp_status = pkt->comp_status; bcb->packet_size = packet_size; nbcb = bcb; /* Prepare any linked buffers */ for (linked_bcb_cnt = 1; ; linked_bcb_cnt++) { if (packet_size > rec_data_size) { nbcb->rec_data_size = rec_data_size; packet_size -= rec_data_size; /* * If split buffer, only use header size on 1st buffer */ rec_data_size = ha->receive_buff_data_size; handle = iprec_entry->buffer_handles[linked_bcb_cnt]; if (handle >= ha->max_receive_buffers) { /* * Invalid handle from RISC reset RISC firmware */ printk(KERN_WARNING "%s: Bad IP buffer handle %x (> " "buffer_count - PS)...Post ISP Abort\n", __func__, handle); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); return; } nbcb->next_bcb = &ha->receive_buffers[handle]; nbcb = nbcb->next_bcb; if (!test_and_clear_bit(BCB_RISC_OWNS_BUFFER, &nbcb->state)) { /* * Invalid handle from RISC reset RISC firmware */ printk(KERN_WARNING "%s: Bad IP buffer handle %x " "(!RISC_owned - PS)...Post ISP Abort\n", __func__, handle); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); return; } } else { /* Single buffer_cb */ nbcb->rec_data_size = packet_size; nbcb->next_bcb = NULL; break; } } /* Check for incoming ARP packet with matching IP address */ if (iprec_entry->service_class == 0) { uint8_t port_id[3]; struct ip_device *ipdev; struct packet_header *packethdr; packethdr = (struct packet_header *)bcb->skb_data; /* Scan list of IP devices to see if login needed */ for (ipdev = ha->ipdev_db_top; ipdev; ipdev = ipdev->next) { if (!memcmp(&ipdev->port_name[2], packethdr->networkh.s.na.addr, ETH_ALEN)) { /* Device already in IP list, skip login */ goto skip_device_login; } } /* Device not in list, need to do login */ port_id[2] = iprec_entry->s_idhigh; port_id[1] = MSB(iprec_entry->s_idlow); port_id[0] = LSB(iprec_entry->s_idlow); /* Make sure its not a local device */ if (port_id[2] == ha->d_id.b.domain && port_id[1] == ha->d_id.b.area) { goto skip_device_login; } if (qla2x00_add_new_ip_device(ha, PUBLIC_LOOP_DEVICE, port_id, packethdr->networkh.s.fcaddr, TRUE, 1) == QL_STATUS_FATAL_ERROR) { /* Fatal error, reinitialize */ set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); } }skip_device_login: /* Pass received packet to IP driver */ bcb->linked_bcb_cnt = linked_bcb_cnt; (*ha->receive_packets_routine)(ha->receive_packets_context, bcb); /* Keep track of RISC buffer pointer (for IP reinit) */ ha->rec_entries_out += linked_bcb_cnt; if (ha->rec_entries_out >= IP_BUFFER_QUEUE_DEPTH) ha->rec_entries_out -= IP_BUFFER_QUEUE_DEPTH;}/** * qla2x00_ip_receive_fastpost() - Handle IP receive fastpost. * @ha: SCSI driver HA context * @type: RISC fastpost type * * Upon preparation of one or more buffer_cbs, the IP driver is notified of * the received packet. */static voidqla2x00_ip_receive_fastpost(scsi_qla_host_t *ha, uint16_t type){ uint32_t handle; uint32_t packet_size; uint16_t linked_bcb_cnt; uint32_t rec_data_size; volatile uint16_t *next_mb; device_reg_t *reg = ha->iobase; struct buffer_cb *bcb; struct buffer_cb *nbcb; DEBUG12(printk("%s: enter\n", __func__);) next_mb = ®->mailbox10; /* If split buffer, set header size for 1st buffer */ if (type == MBA_IP_RECEIVE_COMPLETE_SPLIT) rec_data_size = ha->header_size; else rec_data_size = ha->receive_buff_data_size; handle = RD_REG_WORD(next_mb); if (handle >= ha->max_receive_buffers) { goto invalid_handle; } bcb = &ha->receive_buffers[handle]; if (!test_and_clear_bit(BCB_RISC_OWNS_BUFFER, &bcb->state)) { goto invalid_handle; } packet_size = RD_REG_WORD(®->mailbox3); /* Fastpost entries are always successfully transferred */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?