qla_ip.c

来自「这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自」· C语言 代码 · 共 1,757 行 · 第 1/4 页

C
1,757
字号
	bcb->comp_status = CS_COMPLETE;	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;			next_mb++;			handle = RD_REG_WORD(next_mb);			if (handle >= ha->max_receive_buffers) {invalid_handle:				printk(KERN_WARNING					"%s: bad IP receive fast post handle "					"%x\n", 					__func__,					handle);				set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);				/* Clear interrupt - before leaving */				WRT_REG_WORD(&reg->host_cmd, HC_CLR_RISC_INT);#if defined(ISP2200)				WRT_REG_WORD(&reg->semaphore, 0);#endif				return;			}			nbcb->next_bcb = &ha->receive_buffers[handle];			nbcb = nbcb->next_bcb;			if (!test_and_clear_bit(BCB_RISC_OWNS_BUFFER,							&nbcb->state)) {				goto invalid_handle;			}		}		else {			/* Single buffer_cb */			nbcb->rec_data_size = packet_size;			nbcb->next_bcb = NULL;			break;		}	}	/* Clear interrupt */	WRT_REG_WORD(&reg->host_cmd, HC_CLR_RISC_INT);#if defined(ISP2200)	WRT_REG_WORD(&reg->semaphore, 0);#endif	/* 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_convert_to_arp() - Convert an IP send packet to an ARP packet * @ha: SCSI driver HA context * @scb: The send_cb structure to convert * * Returns TRUE if conversion successful. */static intqla2x00_convert_to_arp(scsi_qla_host_t *ha, struct send_cb *scb){	struct sk_buff		*skb;	struct packet_header	*packethdr;	struct arp_header	*arphdr;	struct ip_header	*iphdr;	DEBUG12(printk("%s: convert packet to ARP\n", __func__);)	skb = scb->skb;	packethdr = scb->header;	arphdr = (struct arp_header *)skb->data;	iphdr  = (struct ip_header *)skb->data;	if (packethdr->snaph.ethertype == __constant_htons(ETH_P_IP)) {		/* Convert IP packet to ARP packet */		packethdr->networkh.d.na.naa = NAA_IEEE_MAC_TYPE;		packethdr->networkh.d.na.unused = 0;		memcpy(packethdr->networkh.d.na.addr,				hwbroadcast_addr, ETH_ALEN);		packethdr->snaph.ethertype = __constant_htons(ETH_P_ARP);		arphdr->ar_tip = iphdr->iph.daddr;		arphdr->ar_sip = iphdr->iph.saddr;		arphdr->arph.ar_hrd = __constant_htons(ARPHRD_IEEE802);		arphdr->arph.ar_pro = __constant_htons(ETH_P_IP);		arphdr->arph.ar_hln = ETH_ALEN;		arphdr->arph.ar_pln = sizeof(iphdr->iph.daddr); /* 4 */		arphdr->arph.ar_op = __constant_htons(ARPOP_REQUEST);		memcpy(arphdr->ar_sha, packethdr->networkh.s.na.addr, ETH_ALEN);		memset(arphdr->ar_tha, 0, ETH_ALEN);		skb->len = sizeof(struct arp_header);		return (TRUE);	}	else {		return (FALSE);	}}/** * qla2x00_get_ip_loopid() - Retrieve loop id of an IP device. * @ha: SCSI driver HA context * @packethdr: IP device to remove * @loop_id: loop id of discovered device * * This routine will interrogate the packet header to determine if the sender is * in the list of active IP devices.  The first two bytes of the destination * address will be modified to match the port name stored in the active IP * device list. * * Returns TRUE if a valid loop id is returned. */static intqla2x00_get_ip_loopid(scsi_qla_host_t *ha,		struct packet_header *packethdr, uint8_t *loop_id){	struct ip_device *ipdev;	/* Scan list of logged in IP devices for match */	for (ipdev = ha->ipdev_db_top; ipdev; ipdev = ipdev->next) {		if (memcmp(&ipdev->port_name[2],				&(packethdr->networkh.d.fcaddr[2]), ETH_ALEN))			continue;		/* Found match, return loop ID  */		*loop_id = (uint8_t)ipdev->loop_id;		/* Update first 2 bytes of port name */		packethdr->networkh.d.fcaddr[0] = ipdev->port_name[0];		packethdr->networkh.d.fcaddr[1] = ipdev->port_name[1];		if (ipdev != ha->ipdev_db_top) {			/* Device not at top, move it to top of list */			/* Unhook it first */			if (ipdev == ha->ipdev_db_bottom) {				ha->ipdev_db_bottom = ipdev->last;				ipdev->last->next = NULL;			}			else {				ipdev->last->next = ipdev->next;				ipdev->next->last = ipdev->last;			}			/* Now put it at top of list */			ipdev->next = ha->ipdev_db_top;			ipdev->last = NULL;			ha->ipdev_db_top->last = ipdev;			ha->ipdev_db_top = ipdev;		}		return (TRUE);	}	/* Check for broadcast packet */	if (!memcmp(packethdr->networkh.d.na.addr,				hwbroadcast_addr, ETH_ALEN)) {		/* Broadcast packet, return broadcast loop ID  */		*loop_id = BROADCAST;		/* Update destination NAA of header */		packethdr->networkh.d.na.naa = NAA_IEEE_MAC_TYPE;		packethdr->networkh.d.na.unused = 0;		return (TRUE);	}	/* Check for multicast packet */	if (packethdr->networkh.d.na.addr[0] & 0x01) {		/* Use broadcast loop ID for multicast packets  */		*loop_id = BROADCAST;		/* Update destination NAA of header */		packethdr->networkh.d.na.naa = NAA_IEEE_MAC_TYPE;		packethdr->networkh.d.na.unused = 0;		return (TRUE);	}	/* TODO */	/* Try sending FARP IOCB to request login */	DEBUG12(printk("%s: ID not found for "			"XX XX %02x %02x %02x %02x %02x %02x\n",			__func__,			packethdr->networkh.d.na.addr[0],			packethdr->networkh.d.na.addr[1],			packethdr->networkh.d.na.addr[2],			packethdr->networkh.d.na.addr[3],			packethdr->networkh.d.na.addr[4],			packethdr->networkh.d.na.addr[5]);)	return (FALSE);}/** * qla2x00_reserve_loopid() - Reserve an unused public loop id. * @ha: SCSI driver HA context * @loop_id: loop id reserved * * Returns QL_STATUS_SUCCESS if a valid loop id is returned. */static intqla2x00_reserve_loopid(scsi_qla_host_t *ha, uint16_t *loop_id){	int i;	/* Look for unused loop ID */	for (i = ha->min_external_loopid; i < ha->max_public_loop_ids; i++) {		if (ha->fabricid[i].in_use)			continue;		/* Found free loop ID */		ha->fabricid[i].in_use = TRUE;		*loop_id = i;		DEBUG12(printk("%s: assigned loop ID %x\n",				__func__,				*loop_id);)		return (QL_STATUS_SUCCESS);	}	/* Out of loop IDs */	*loop_id = ha->max_public_loop_ids + 1;     /* Set out of range */	DEBUG12(printk("%s: out of loop IDs\n", __func__);)	return (QL_STATUS_RESOURCE_ERROR);}/** * qla2x00_free_loopid() - Free a public loop id. * @ha: SCSI driver HA context * @loop_id: loop id to free */static voidqla2x00_free_loopid(scsi_qla_host_t *ha, uint16_t loop_id){	if (loop_id < ha->max_public_loop_ids) {		ha->fabricid[loop_id].in_use = FALSE;		DEBUG12(printk("%s: free loop ID %x\n",				__func__,				loop_id);)	}	else {		DEBUG12(printk("%s: loop ID %x out of range\n",				__func__,				loop_id);)	}}/** * qla2x00_add_new_ip_device() - Add a new IP capable device to the list. * @ha: SCSI driver HA context * @loop_id: loop id, if a private loop, of the new device * @port_id: port id of the new device * @port_name: port name of the new device * @force_add: should the function force the addition of the device * @ha_locked: Flag indicating if the function is called with the hardware lock * * Prior to RISC IP initialization, this routine, if necessary, will reset all * buffers in the receive buffer ring. * * Returns QL_STATUS_SUCCESS if there were no errors adding the device. */static intqla2x00_add_new_ip_device(scsi_qla_host_t *ha,			     uint16_t loop_id,			     uint8_t *port_id,			     uint8_t *port_name,			     int force_add,			     uint32_t ha_locked){	int	status;	struct ip_device *ipdev;	/* Get free IP device block */	status = qla2x00_reserve_ip_block(ha, &ipdev);	if (status == QL_STATUS_RESOURCE_ERROR) {		if (!force_add)			return (status);		/*		 * Out of IP blocks, bump public device at bottom of list		 */		DEBUG12(printk("%s: bump device from IP list\n", __func__);)		for (ipdev = ha->ipdev_db_bottom; ipdev; ipdev = ipdev->last) {			if (!(ipdev->flags & IP_DEV_FLAG_PUBLIC_DEVICE))				continue;			/* Do fabric logout and free loop ID */			qla2x00_ip_send_logout_port_iocb(ha, ipdev, ha_locked);			qla2x00_free_loopid(ha, ipdev->loop_id);			/* Move device to top of list */			qla2x00_free_ip_block(ha, ipdev);			status = qla2x00_reserve_ip_block(ha, &ipdev);			break;		}		if (status != QL_STATUS_SUCCESS)			return (status);	}	/* Save IP port name */	memcpy(ipdev->port_name, port_name, WWN_SIZE);	if (loop_id != PUBLIC_LOOP_DEVICE) {		/* Private loop device */		ipdev->loop_id = loop_id;		ipdev->flags = IP_DEV_FLAG_PRESENT;		DEBUG12(printk("%s: WWN:%02x%02x%02x%02x%02x%02x%02x%02x, "				"LoopID:%x\n",				__func__,				ipdev->port_name[0],				ipdev->port_name[1],				ipdev->port_name[2],				ipdev->port_name[3],				ipdev->port_name[4],				ipdev->port_name[5],				ipdev->port_name[6],				ipdev->port_name[7],				ipdev->loop_id);)	}	else {		/* Public device */		/* Reserve public loop ID, save it in database */		status = qla2x00_reserve_loopid(ha, &ipdev->loop_id);		if (status == QL_STATUS_RESOURCE_ERROR) {			struct ip_device *ipdev_bump;			if (!force_add) { 				/* Failed to get loop ID */				DEBUG12(printk("%s: failed to get loop ID\n",						__func__);)				qla2x00_free_ip_block(ha, ipdev);				return (status);			}			/*			 * Out of loop IDs, bump public device at bottom of			 * list.			 */			DEBUG12(printk("%s: bump device from IP list\n",					__func__);)			for (ipdev_bump = ha->ipdev_db_bottom;				ipdev_bump;				ipdev_bump = ipdev_bump->last) {				if (!(ipdev_bump->flags &						IP_DEV_FLAG_PUBLIC_DEVICE))					continue;				/*				 * Do fabric logout, steal loop ID, free bumped				 * IP block.				 */				qla2x00_ip_send_logout_port_iocb(ha,						ipdev_bump, ha_locked);				ipdev->loop_id = ipdev_bump->loop_id;				qla2x00_free_ip_block(ha, ipdev_bump);				status = QL_STATUS_SUCCESS;				break;			}			if (status != QL_STATUS_SUCCESS) {				/* Failed to get loop ID */				DEBUG12(printk("%s: failed to get loop ID\n",						__func__);)				qla2x00_free_ip_block(ha, ipdev);				return (status);			}		}		/* Save device data */		ipdev->port_id[0] = port_id[0];		ipdev->port_id[1] = port_id[1];		ipdev->port_id[2] = port_id[2];		ipdev->flags = IP_DEV_FLAG_PUBLIC_DEVICE;		/* Login public device */		status = qla2x00_ip_send_login_port_iocb(ha, ipdev, ha_locked);		if (status == QL_STATUS_SUCCESS) {			DEBUG12(printk("%s: "					"WWN:%02x%02x%02x%02x%02x%02x%02x%02x, "					"LoopID:%x, PortID:%x\n",					__func__,					ipdev->port_name[0],					ipdev->port_name[1],					ipdev->port_name[2],					ipdev->port_name[3],					ipdev->port_name[4],					ipdev->port_name[5],					ipdev->port_name[6],					ipdev->port_name[7],					ipdev->loop_id,					ipdev->port_id[2]<<16 |					ipdev->port_id[1]<<8 |					ipdev->port_id[0]);)		}		else {			/* Login failed, return resources */			qla2x00_free_loopid(ha, ipdev->loop_id);			qla2x00_free_ip_block(ha, ipdev);		}	}	return (status);}/** * qla2x00_free_ip_block() - Remove an IP device from the active IP list. * @ha: SCSI driver HA context * @ipdev: IP device to remove */static voidqla2x00_free_ip_block(scsi_qla_host_t *ha, struct ip_device *ipdev){	/* Unhook IP device block from active list */	if (ipdev->last == NULL)

⌨️ 快捷键说明

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