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(®->host_cmd, HC_CLR_RISC_INT);#if defined(ISP2200) WRT_REG_WORD(®->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(®->host_cmd, HC_CLR_RISC_INT);#if defined(ISP2200) WRT_REG_WORD(®->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 + -
显示快捷键?