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(&reg->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 = &reg->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(&reg->mailbox3);	/* Fastpost entries are always successfully transferred */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?