From 0e43895ec1f405a25b5d57bc95c11fe17224ec43 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 3 Apr 2012 23:41:51 -0500 Subject: [SCSI] be2iscsi: adding functionality to change network settings using iscsiadm This patch allows iscsiadm to set/ delete static IP and enable /disable DHCP. Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index b15de3e..60d1445 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -163,7 +163,8 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES 3 #define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7 #define OPCODE_COMMON_ISCSI_NTWK_SET_VLAN 14 -#define OPCODE_COMMON_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR 17 +#define OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR 17 +#define OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR 18 #define OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR 21 #define OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY 22 #define OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY 23 @@ -274,15 +275,15 @@ struct mgmt_conn_login_options { struct mgmt_auth_method_format auth_data; } __packed; -struct ip_address_format { +struct ip_addr_format { u16 size_of_structure; u8 reserved; u8 ip_type; - u8 ip_address[16]; + u8 addr[16]; u32 rsvd0; } __packed; -struct mgmt_conn_info { +struct mgmt_conn_info { u32 connection_handle; u32 connection_status; u16 src_port; @@ -290,9 +291,9 @@ struct mgmt_conn_info { u16 dest_port_redirected; u16 cid; u32 estimated_throughput; - struct ip_address_format src_ipaddr; - struct ip_address_format dest_ipaddr; - struct ip_address_format dest_ipaddr_redirected; + struct ip_addr_format src_ipaddr; + struct ip_addr_format dest_ipaddr; + struct ip_addr_format dest_ipaddr_redirected; struct mgmt_conn_login_options negotiated_login_options; } __packed; @@ -322,43 +323,115 @@ struct mgmt_session_info { struct mgmt_conn_info conn_list[1]; } __packed; -struct be_cmd_req_get_session { +struct be_cmd_get_session_req { struct be_cmd_req_hdr hdr; u32 session_handle; } __packed; -struct be_cmd_resp_get_session { +struct be_cmd_get_session_resp { struct be_cmd_resp_hdr hdr; struct mgmt_session_info session_info; } __packed; struct mac_addr { - u16 size_of_struct; + u16 size_of_structure; u8 addr[ETH_ALEN]; } __packed; -struct be_cmd_req_get_boot_target { +struct be_cmd_get_boot_target_req { struct be_cmd_req_hdr hdr; } __packed; -struct be_cmd_resp_get_boot_target { +struct be_cmd_get_boot_target_resp { struct be_cmd_resp_hdr hdr; u32 boot_session_count; int boot_session_handle; }; -struct be_cmd_req_mac_query { +struct be_cmd_mac_query_req { struct be_cmd_req_hdr hdr; u8 type; u8 permanent; u16 if_id; } __packed; -struct be_cmd_resp_mac_query { +struct be_cmd_get_mac_resp { struct be_cmd_resp_hdr hdr; struct mac_addr mac; }; +struct be_ip_addr_subnet_format { + u16 size_of_structure; + u8 ip_type; + u8 ipv6_prefix_length; + u8 addr[16]; + u8 subnet_mask[16]; + u32 rsvd0; +} __packed; + +struct be_cmd_get_if_info_req { + struct be_cmd_req_hdr hdr; + u32 interface_hndl; + u32 ip_type; +} __packed; + +struct be_cmd_get_if_info_resp { + struct be_cmd_req_hdr hdr; + u32 interface_hndl; + u32 vlan_priority; + u32 ip_addr_count; + u32 dhcp_state; + struct be_ip_addr_subnet_format ip_addr; +} __packed; + +struct be_ip_addr_record { + u32 action; + u32 interface_hndl; + struct be_ip_addr_subnet_format ip_addr; + u32 status; +} __packed; + +struct be_ip_addr_record_params { + u32 record_entry_count; + struct be_ip_addr_record ip_record; +} __packed; + +struct be_cmd_set_ip_addr_req { + struct be_cmd_req_hdr hdr; + struct be_ip_addr_record_params ip_params; +} __packed; + + +struct be_cmd_set_dhcp_req { + struct be_cmd_req_hdr hdr; + u32 interface_hndl; + u32 ip_type; + u32 flags; + u32 retry_count; +} __packed; + +struct be_cmd_rel_dhcp_req { + struct be_cmd_req_hdr hdr; + u32 interface_hndl; + u32 ip_type; +} __packed; + +struct be_cmd_set_def_gateway_req { + struct be_cmd_req_hdr hdr; + u32 action; + struct ip_addr_format ip_addr; +} __packed; + +struct be_cmd_get_def_gateway_req { + struct be_cmd_req_hdr hdr; + u32 ip_type; +} __packed; + +struct be_cmd_get_def_gateway_resp { + struct be_cmd_req_hdr hdr; + struct ip_addr_format ip_addr; +} __packed; + /******************** Create CQ ***************************/ /** * Pseudo amap definition in which each bit of the actual structure is defined @@ -489,7 +562,7 @@ struct be_cmd_req_modify_eq_delay { #define ETH_ALEN 6 -struct be_cmd_req_get_mac_addr { +struct be_cmd_get_nic_conf_req { struct be_cmd_req_hdr hdr; u32 nic_port_count; u32 speed; @@ -501,7 +574,7 @@ struct be_cmd_req_get_mac_addr { u32 rsvd[23]; }; -struct be_cmd_resp_get_mac_addr { +struct be_cmd_get_nic_conf_resp { struct be_cmd_resp_hdr hdr; u32 nic_port_count; u32 speed; @@ -541,12 +614,7 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, int be_poll_mcc(struct be_ctrl_info *ctrl); int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); -unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba); unsigned int be_cmd_get_initname(struct beiscsi_hba *phba); -unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba); -unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd); void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag); /*ISCSI Functuions */ @@ -727,7 +795,7 @@ struct be_eq_delay_params_in { struct tcp_connect_and_offload_in { struct be_cmd_req_hdr hdr; - struct ip_address_format ip_address; + struct ip_addr_format ip_address; u16 tcp_port; u16 cid; u16 cq_id; @@ -804,7 +872,7 @@ struct be_fw_cfg { u32 function_caps; } __packed; -struct be_all_if_id { +struct be_cmd_get_all_if_id_req { struct be_cmd_req_hdr hdr; u32 if_count; u32 if_hndl_list[1]; diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 1af7774..46cc40e 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include "be_iscsi.h" @@ -207,6 +209,301 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); } +static int beiscsi_create_ipv4_iface(struct beiscsi_hba *phba) +{ + if (phba->ipv4_iface) + return 0; + + phba->ipv4_iface = iscsi_create_iface(phba->shost, + &beiscsi_iscsi_transport, + ISCSI_IFACE_TYPE_IPV4, + 0, 0); + if (!phba->ipv4_iface) { + shost_printk(KERN_ERR, phba->shost, "Could not " + "create default IPv4 address.\n"); + return -ENODEV; + } + + return 0; +} + +static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba) +{ + if (phba->ipv6_iface) + return 0; + + phba->ipv6_iface = iscsi_create_iface(phba->shost, + &beiscsi_iscsi_transport, + ISCSI_IFACE_TYPE_IPV6, + 0, 0); + if (!phba->ipv6_iface) { + shost_printk(KERN_ERR, phba->shost, "Could not " + "create default IPv6 address.\n"); + return -ENODEV; + } + + return 0; +} + +void beiscsi_create_def_ifaces(struct beiscsi_hba *phba) +{ + struct be_cmd_get_if_info_resp if_info; + + if (!mgmt_get_if_info(phba, BE2_IPV4, &if_info)) + beiscsi_create_ipv4_iface(phba); + + if (!mgmt_get_if_info(phba, BE2_IPV6, &if_info)) + beiscsi_create_ipv6_iface(phba); +} + +void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba) +{ + if (phba->ipv6_iface) + iscsi_destroy_iface(phba->ipv6_iface); + if (phba->ipv4_iface) + iscsi_destroy_iface(phba->ipv4_iface); +} + +static int +beiscsi_set_static_ip(struct Scsi_Host *shost, + struct iscsi_iface_param_info *iface_param, + void *data, uint32_t dt_len) +{ + struct beiscsi_hba *phba = iscsi_host_priv(shost); + struct iscsi_iface_param_info *iface_ip = NULL; + struct iscsi_iface_param_info *iface_subnet = NULL; + struct nlattr *nla; + int ret; + + + switch (iface_param->param) { + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); + if (nla) + iface_ip = nla_data(nla); + + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); + if (nla) + iface_subnet = nla_data(nla); + break; + case ISCSI_NET_PARAM_IPV4_ADDR: + iface_ip = iface_param; + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); + if (nla) + iface_subnet = nla_data(nla); + break; + case ISCSI_NET_PARAM_IPV4_SUBNET: + iface_subnet = iface_param; + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); + if (nla) + iface_ip = nla_data(nla); + break; + default: + shost_printk(KERN_ERR, shost, "Unsupported param %d\n", + iface_param->param); + } + + if (!iface_ip || !iface_subnet) { + shost_printk(KERN_ERR, shost, "IP and Subnet Mask required\n"); + return -EINVAL; + } + + ret = mgmt_set_ip(phba, iface_ip, iface_subnet, + ISCSI_BOOTPROTO_STATIC); + + return ret; +} + +static int +beiscsi_set_ipv4(struct Scsi_Host *shost, + struct iscsi_iface_param_info *iface_param, + void *data, uint32_t dt_len) +{ + struct beiscsi_hba *phba = iscsi_host_priv(shost); + int ret = 0; + + /* Check the param */ + switch (iface_param->param) { + case ISCSI_NET_PARAM_IPV4_GW: + ret = mgmt_set_gateway(phba, iface_param); + break; + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) + ret = mgmt_set_ip(phba, iface_param, + NULL, ISCSI_BOOTPROTO_DHCP); + else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) + ret = beiscsi_set_static_ip(shost, iface_param, + data, dt_len); + else + shost_printk(KERN_ERR, shost, "Invalid BOOTPROTO: %d\n", + iface_param->value[0]); + break; + case ISCSI_NET_PARAM_IFACE_ENABLE: + if (iface_param->value[0] == ISCSI_IFACE_ENABLE) + ret = beiscsi_create_ipv4_iface(phba); + else + iscsi_destroy_iface(phba->ipv4_iface); + break; + case ISCSI_NET_PARAM_IPV4_SUBNET: + case ISCSI_NET_PARAM_IPV4_ADDR: + ret = beiscsi_set_static_ip(shost, iface_param, + data, dt_len); + break; + default: + shost_printk(KERN_ERR, shost, "Param %d not supported\n", + iface_param->param); + } + + return ret; +} + +static int +beiscsi_set_ipv6(struct Scsi_Host *shost, + struct iscsi_iface_param_info *iface_param, + void *data, uint32_t dt_len) +{ + struct beiscsi_hba *phba = iscsi_host_priv(shost); + int ret = 0; + + switch (iface_param->param) { + case ISCSI_NET_PARAM_IFACE_ENABLE: + if (iface_param->value[0] == ISCSI_IFACE_ENABLE) + ret = beiscsi_create_ipv6_iface(phba); + else { + iscsi_destroy_iface(phba->ipv6_iface); + ret = 0; + } + break; + case ISCSI_NET_PARAM_IPV6_ADDR: + ret = mgmt_set_ip(phba, iface_param, NULL, + ISCSI_BOOTPROTO_STATIC); + break; + default: + shost_printk(KERN_ERR, shost, "Param %d not supported\n", + iface_param->param); + } + + return ret; +} + +int be2iscsi_iface_set_param(struct Scsi_Host *shost, + void *data, uint32_t dt_len) +{ + struct iscsi_iface_param_info *iface_param = NULL; + struct nlattr *attrib; + uint32_t rm_len = dt_len; + int ret = 0 ; + + nla_for_each_attr(attrib, data, dt_len, rm_len) { + iface_param = nla_data(attrib); + + if (iface_param->param_type != ISCSI_NET_PARAM) + continue; + + /* + * BE2ISCSI only supports 1 interface + */ + if (iface_param->iface_num) { + shost_printk(KERN_ERR, shost, "Invalid iface_num %d." + "Only iface_num 0 is supported.\n", + iface_param->iface_num); + return -EINVAL; + } + + switch (iface_param->iface_type) { + case ISCSI_IFACE_TYPE_IPV4: + ret = beiscsi_set_ipv4(shost, iface_param, + data, dt_len); + break; + case ISCSI_IFACE_TYPE_IPV6: + ret = beiscsi_set_ipv6(shost, iface_param, + data, dt_len); + break; + default: + shost_printk(KERN_ERR, shost, + "Invalid iface type :%d passed\n", + iface_param->iface_type); + break; + } + + if (ret) + return ret; + } + + return ret; +} + +static int be2iscsi_get_if_param(struct beiscsi_hba *phba, + struct iscsi_iface *iface, int param, + char *buf) +{ + struct be_cmd_get_if_info_resp if_info; + int len, ip_type = BE2_IPV4; + + memset(&if_info, 0, sizeof(if_info)); + + if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) + ip_type = BE2_IPV6; + + len = mgmt_get_if_info(phba, ip_type, &if_info); + if (len) + return len; + + switch (param) { + case ISCSI_NET_PARAM_IPV4_ADDR: + len = sprintf(buf, "%pI4\n", &if_info.ip_addr.addr); + break; + case ISCSI_NET_PARAM_IPV6_ADDR: + len = sprintf(buf, "%pI6\n", &if_info.ip_addr.addr); + break; + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + if (!if_info.dhcp_state) + len = sprintf(buf, "static"); + else + len = sprintf(buf, "dhcp"); + break; + case ISCSI_NET_PARAM_IPV4_SUBNET: + len = sprintf(buf, "%pI4\n", &if_info.ip_addr.subnet_mask); + break; + default: + WARN_ON(1); + } + + return len; +} + +int be2iscsi_iface_get_param(struct iscsi_iface *iface, + enum iscsi_param_type param_type, + int param, char *buf) +{ + struct Scsi_Host *shost = iscsi_iface_to_shost(iface); + struct beiscsi_hba *phba = iscsi_host_priv(shost); + struct be_cmd_get_def_gateway_resp gateway; + int len = -ENOSYS; + + switch (param) { + case ISCSI_NET_PARAM_IPV4_ADDR: + case ISCSI_NET_PARAM_IPV4_SUBNET: + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + case ISCSI_NET_PARAM_IPV6_ADDR: + len = be2iscsi_get_if_param(phba, iface, param, buf); + break; + case ISCSI_NET_PARAM_IFACE_ENABLE: + len = sprintf(buf, "enabled"); + break; + case ISCSI_NET_PARAM_IPV4_GW: + memset(&gateway, 0, sizeof(gateway)); + len = mgmt_get_gateway(phba, BE2_IPV4, &gateway); + if (!len) + len = sprintf(buf, "%pI4\n", &gateway.ip_addr.addr); + break; + default: + len = -ENOSYS; + } + + return len; +} + /** * beiscsi_ep_get_param - get the iscsi parameter * @ep: pointer to iscsi ep @@ -359,46 +656,21 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba) { - struct be_cmd_resp_get_mac_addr *resp; - struct be_mcc_wrb *wrb; - unsigned int tag, wrb_num; - unsigned short status, extd_status; - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + struct be_cmd_get_nic_conf_resp resp; int rc; - if (phba->read_mac_address) - return sysfs_format_mac(buf, phba->mac_address, - ETH_ALEN); + if (strlen(phba->mac_address)) + return strlcpy(buf, phba->mac_address, PAGE_SIZE); - tag = be_cmd_get_mac_addr(phba); - if (!tag) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); - return -EBUSY; - } else - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); + memset(&resp, 0, sizeof(resp)); + rc = mgmt_get_nic_conf(phba, &resp); + if (rc) + return rc; - wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; - extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; - status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; - if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "Failed to get be_cmd_get_mac_addr" - " status = %d extd_status = %d\n", - status, extd_status); - free_mcc_tag(&phba->ctrl, tag); - return -EAGAIN; - } - wrb = queue_get_wrb(mccq, wrb_num); - free_mcc_tag(&phba->ctrl, tag); - resp = embedded_payload(wrb); - memcpy(phba->mac_address, resp->mac_address, ETH_ALEN); - rc = sysfs_format_mac(buf, phba->mac_address, - ETH_ALEN); - phba->read_mac_address = 1; - return rc; + memcpy(phba->mac_address, resp.mac_address, ETH_ALEN); + return sysfs_format_mac(buf, phba->mac_address, ETH_ALEN); } - /** * beiscsi_conn_get_stats - get the iscsi stats * @cls_conn: pointer to iscsi cls conn @@ -786,11 +1058,21 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) umode_t be2iscsi_attr_is_visible(int param_type, int param) { switch (param_type) { + case ISCSI_NET_PARAM: + switch (param) { + case ISCSI_NET_PARAM_IFACE_ENABLE: + case ISCSI_NET_PARAM_IPV4_ADDR: + case ISCSI_NET_PARAM_IPV4_SUBNET: + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + case ISCSI_NET_PARAM_IPV4_GW: + case ISCSI_NET_PARAM_IPV6_ADDR: + return S_IRUGO; + default: + return 0; + } case ISCSI_HOST_PARAM: switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_IPADDRESS: - case ISCSI_HOST_PARAM_INITIATOR_NAME: return S_IRUGO; default: return 0; diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index 5c45be1..8b826fc 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -25,6 +25,21 @@ #define BE2_IPV4 0x1 #define BE2_IPV6 0x10 +#define BE2_DHCP_V4 0x05 + +#define NON_BLOCKING 0x0 +#define BLOCKING 0x1 + +void beiscsi_create_def_ifaces(struct beiscsi_hba *phba); + +void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba); + +int be2iscsi_iface_get_param(struct iscsi_iface *iface, + enum iscsi_param_type param_type, + int param, char *buf); + +int be2iscsi_iface_set_param(struct Scsi_Host *shost, + void *data, uint32_t count); umode_t be2iscsi_attr_is_visible(int param_type, int param); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index ff6f851..0b1d99c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -231,10 +231,10 @@ static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) case ISCSI_BOOT_TGT_IP_ADDR: if (boot_conn->dest_ipaddr.ip_type == 0x1) rc = sprintf(buf, "%pI4\n", - (char *)&boot_conn->dest_ipaddr.ip_address); + (char *)&boot_conn->dest_ipaddr.addr); else rc = sprintf(str, "%pI6\n", - (char *)&boot_conn->dest_ipaddr.ip_address); + (char *)&boot_conn->dest_ipaddr.addr); break; case ISCSI_BOOT_TGT_PORT: rc = sprintf(str, "%d\n", boot_conn->dest_port); @@ -312,12 +312,8 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) rc = sprintf(str, "0\n"); break; case ISCSI_BOOT_ETH_MAC: - rc = beiscsi_get_macaddr(buf, phba); - if (rc < 0) { - SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n"); - return rc; - } - break; + rc = beiscsi_get_macaddr(str, phba); + break; default: rc = -ENOSYS; break; @@ -438,6 +434,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) phba->shost = shost; phba->pcidev = pci_dev_get(pcidev); pci_set_drvdata(pcidev, phba); + phba->interface_handle = 0xFFFFFFFF; if (iscsi_host_add(shost, &phba->pcidev->dev)) goto free_devices; @@ -3471,8 +3468,8 @@ static void hwi_disable_intr(struct beiscsi_hba *phba) static int beiscsi_get_boot_info(struct beiscsi_hba *phba) { - struct be_cmd_resp_get_boot_target *boot_resp; - struct be_cmd_resp_get_session *session_resp; + struct be_cmd_get_boot_target_resp *boot_resp; + struct be_cmd_get_session_resp *session_resp; struct be_mcc_wrb *wrb; struct be_dma_mem nonemb_cmd; unsigned int tag, wrb_num; @@ -3480,9 +3477,9 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; int ret = -ENOMEM; - tag = beiscsi_get_boot_target(phba); + tag = mgmt_get_boot_target(phba); if (!tag) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); + SE_DEBUG(DBG_LVL_1, "beiscsi_get_boot_info Failed\n"); return -EAGAIN; } else wait_event_interruptible(phba->ctrl.mcc_wait[tag], @@ -3492,7 +3489,7 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" + SE_DEBUG(DBG_LVL_1, "beiscsi_get_boot_info Failed" " status = %d extd_status = %d\n", status, extd_status); free_mcc_tag(&phba->ctrl, tag); @@ -3518,8 +3515,8 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) } memset(nonemb_cmd.va, 0, sizeof(*session_resp)); - tag = beiscsi_get_session_info(phba, - boot_resp->boot_session_handle, &nonemb_cmd); + tag = mgmt_get_session_info(phba, boot_resp->boot_session_handle, + &nonemb_cmd); if (!tag) { SE_DEBUG(DBG_LVL_1, "beiscsi_get_session_info" " Failed\n"); @@ -4267,6 +4264,7 @@ static void beiscsi_remove(struct pci_dev *pcidev) return; } + beiscsi_destroy_def_ifaces(phba); beiscsi_quiesce(phba); iscsi_boot_destroy_kset(phba->boot_kset); iscsi_host_remove(phba->shost); @@ -4453,8 +4451,9 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, * iscsi boot. */ shost_printk(KERN_ERR, phba->shost, "Could not set up " - "iSCSI boot info."); + "iSCSI boot info.\n"); + beiscsi_create_def_ifaces(phba); SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); return 0; @@ -4505,6 +4504,8 @@ struct iscsi_transport beiscsi_iscsi_transport = { .bind_conn = beiscsi_conn_bind, .destroy_conn = iscsi_conn_teardown, .attr_is_visible = be2iscsi_attr_is_visible, + .set_iface_param = be2iscsi_iface_set_param, + .get_iface_param = be2iscsi_iface_get_param, .set_param = beiscsi_set_param, .get_conn_param = iscsi_conn_get_param, .get_session_param = iscsi_session_get_param, diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 13e3bef..40fea6e 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -316,6 +316,8 @@ struct beiscsi_hba { struct iscsi_endpoint **ep_array; struct iscsi_boot_kset *boot_kset; struct Scsi_Host *shost; + struct iscsi_iface *ipv4_iface; + struct iscsi_iface *ipv6_iface; struct { /** * group together since they are used most frequently @@ -345,7 +347,7 @@ struct beiscsi_hba { struct work_struct work_cqs; /* The work being queued */ struct be_ctrl_info ctrl; unsigned int generation; - unsigned int read_mac_address; + unsigned int interface_handle; struct mgmt_session_info boot_sess; struct invalidate_command_table inv_tbl[128]; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index ccc3852..e6cb10d 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -23,11 +23,11 @@ #include "be_mgmt.h" #include "be_iscsi.h" -unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba) +unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; - struct be_cmd_req_get_mac_addr *req; + struct be_cmd_get_boot_target_req *req; unsigned int tag = 0; SE_DEBUG(DBG_LVL_8, "In bescsi_get_boot_target\n"); @@ -44,22 +44,22 @@ unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba) be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, - sizeof(*req)); + sizeof(struct be_cmd_get_boot_target_resp)); be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); return tag; } -unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd) +unsigned int mgmt_get_session_info(struct beiscsi_hba *phba, + u32 boot_session_handle, + struct be_dma_mem *nonemb_cmd) { struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; unsigned int tag = 0; - struct be_cmd_req_get_session *req; - struct be_cmd_resp_get_session *resp; + struct be_cmd_get_session_req *req; + struct be_cmd_get_session_resp *resp; struct be_sge *sge; SE_DEBUG(DBG_LVL_8, "In beiscsi_get_session_info\n"); @@ -396,7 +396,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, struct beiscsi_endpoint *beiscsi_ep, struct be_dma_mem *nonemb_cmd) - { struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; @@ -442,17 +441,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba, if (dst_addr->sa_family == PF_INET) { __be32 s_addr = daddr_in->sin_addr.s_addr; req->ip_address.ip_type = BE2_IPV4; - req->ip_address.ip_address[0] = s_addr & 0x000000ff; - req->ip_address.ip_address[1] = (s_addr & 0x0000ff00) >> 8; - req->ip_address.ip_address[2] = (s_addr & 0x00ff0000) >> 16; - req->ip_address.ip_address[3] = (s_addr & 0xff000000) >> 24; + req->ip_address.addr[0] = s_addr & 0x000000ff; + req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8; + req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16; + req->ip_address.addr[3] = (s_addr & 0xff000000) >> 24; req->tcp_port = ntohs(daddr_in->sin_port); beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr; beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port); beiscsi_ep->ip_type = BE2_IPV4; } else if (dst_addr->sa_family == PF_INET6) { req->ip_address.ip_type = BE2_IPV6; - memcpy(&req->ip_address.ip_address, + memcpy(&req->ip_address.addr, &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); req->tcp_port = ntohs(daddr_in6->sin6_port); beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port); @@ -487,34 +486,392 @@ int mgmt_open_connection(struct beiscsi_hba *phba, return tag; } -unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba) +unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_req_get_mac_addr *req; - unsigned int tag = 0; + struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_cmd_get_all_if_id_req *req = embedded_payload(wrb); + struct be_cmd_get_all_if_id_req *pbe_allid = req; + int status = 0; + + memset(wrb, 0, sizeof(*wrb)); + + spin_lock(&ctrl->mbox_lock); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID, + sizeof(*req)); + status = be_mbox_notify(ctrl); + if (!status) + phba->interface_handle = pbe_allid->if_hndl_list[0]; + else { + shost_printk(KERN_WARNING, phba->shost, + "Failed in mgmt_get_all_if_id\n"); + } + spin_unlock(&ctrl->mbox_lock); + + return status; +} + +static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba, + struct be_dma_mem *nonemb_cmd, void *resp_buf, + int resp_buf_len) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb = wrb_from_mccq(phba); + unsigned short status, extd_status; + struct be_sge *sge; + unsigned int tag; + int rc = 0; - SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n"); spin_lock(&ctrl->mbox_lock); tag = alloc_mcc_tag(phba); if (!tag) { spin_unlock(&ctrl->mbox_lock); - return tag; + rc = -ENOMEM; + goto free_cmd; } - - wrb = wrb_from_mccq(phba); - req = embedded_payload(wrb); + memset(wrb, 0, sizeof(*wrb)); wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, - sizeof(*req)); + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1); + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return tag; + + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, + "mgmt_exec_nonemb_cmd Failed status = %d" + "extd_status = %d\n", status, extd_status); + rc = -EIO; + goto free_tag; + } + + if (resp_buf) + memcpy(resp_buf, nonemb_cmd->va, resp_buf_len); + +free_tag: + free_mcc_tag(&phba->ctrl, tag); +free_cmd: + pci_free_consistent(ctrl->pdev, nonemb_cmd->size, + nonemb_cmd->va, nonemb_cmd->dma); + return rc; +} + +static int mgmt_alloc_cmd_data(struct beiscsi_hba *phba, struct be_dma_mem *cmd, + int iscsi_cmd, int size) +{ + cmd->va = pci_alloc_consistent(phba->ctrl.pdev, sizeof(size), + &cmd->dma); + if (!cmd->va) { + SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for if info\n"); + return -ENOMEM; + } + memset(cmd->va, 0, sizeof(size)); + cmd->size = size; + be_cmd_hdr_prepare(cmd->va, CMD_SUBSYSTEM_ISCSI, iscsi_cmd, size); + return 0; } +static int +mgmt_static_ip_modify(struct beiscsi_hba *phba, + struct be_cmd_get_if_info_resp *if_info, + struct iscsi_iface_param_info *ip_param, + struct iscsi_iface_param_info *subnet_param, + uint32_t ip_action) +{ + struct be_cmd_set_ip_addr_req *req; + struct be_dma_mem nonemb_cmd; + uint32_t ip_type; + int rc; + + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, + sizeof(*req)); + if (rc) + return rc; + + ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? + BE2_IPV6 : BE2_IPV4 ; + + req = nonemb_cmd.va; + req->ip_params.record_entry_count = 1; + req->ip_params.ip_record.action = ip_action; + req->ip_params.ip_record.interface_hndl = + phba->interface_handle; + req->ip_params.ip_record.ip_addr.size_of_structure = + sizeof(struct be_ip_addr_subnet_format); + req->ip_params.ip_record.ip_addr.ip_type = ip_type; + + if (ip_action == IP_ACTION_ADD) { + memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value, + ip_param->len); + + if (subnet_param) + memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, + subnet_param->value, subnet_param->len); + } else { + memcpy(req->ip_params.ip_record.ip_addr.addr, + if_info->ip_addr.addr, ip_param->len); + + memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, + if_info->ip_addr.subnet_mask, ip_param->len); + } + + rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + if (rc < 0) + shost_printk(KERN_WARNING, phba->shost, + "Failed to Modify existing IP Address\n"); + return rc; +} + +static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr, + uint32_t gtway_action, uint32_t param_len) +{ + struct be_cmd_set_def_gateway_req *req; + struct be_dma_mem nonemb_cmd; + int rt_val; + + + rt_val = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY, + sizeof(*req)); + if (rt_val) + return rt_val; + + req = nonemb_cmd.va; + req->action = gtway_action; + req->ip_addr.ip_type = BE2_IPV4; + + memcpy(req->ip_addr.addr, gt_addr, param_len); + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); +} + +int mgmt_set_ip(struct beiscsi_hba *phba, + struct iscsi_iface_param_info *ip_param, + struct iscsi_iface_param_info *subnet_param, + uint32_t boot_proto) +{ + struct be_cmd_get_def_gateway_resp gtway_addr_set; + struct be_cmd_get_if_info_resp if_info; + struct be_cmd_set_dhcp_req *dhcpreq; + struct be_cmd_rel_dhcp_req *reldhcp; + struct be_dma_mem nonemb_cmd; + uint8_t *gtway_addr; + uint32_t ip_type; + int rc; + + if (mgmt_get_all_if_id(phba)) + return -EIO; + + memset(&if_info, 0, sizeof(if_info)); + ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? + BE2_IPV6 : BE2_IPV4 ; + + rc = mgmt_get_if_info(phba, ip_type, &if_info); + if (rc) + return rc; + + if (boot_proto == ISCSI_BOOTPROTO_DHCP) { + if (if_info.dhcp_state) { + shost_printk(KERN_WARNING, phba->shost, + "DHCP Already Enabled\n"); + return 0; + } + /* The ip_param->len is 1 in DHCP case. Setting + proper IP len as this it is used while + freeing the Static IP. + */ + ip_param->len = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? + IP_V6_LEN : IP_V4_LEN; + + } else { + if (if_info.dhcp_state) { + + memset(&if_info, 0, sizeof(if_info)); + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR, + sizeof(*reldhcp)); + + if (rc) + return rc; + + reldhcp = nonemb_cmd.va; + reldhcp->interface_hndl = phba->interface_handle; + reldhcp->ip_type = ip_type; + + rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + if (rc < 0) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to Delete existing dhcp\n"); + return rc; + } + } + } + + /* Delete the Static IP Set */ + if (if_info.ip_addr.addr[0]) { + rc = mgmt_static_ip_modify(phba, &if_info, ip_param, NULL, + IP_ACTION_DEL); + if (rc) + return rc; + } + + /* Delete the Gateway settings if mode change is to DHCP */ + if (boot_proto == ISCSI_BOOTPROTO_DHCP) { + memset(>way_addr_set, 0, sizeof(gtway_addr_set)); + rc = mgmt_get_gateway(phba, BE2_IPV4, >way_addr_set); + if (rc) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to Get Gateway Addr\n"); + return rc; + } + + if (gtway_addr_set.ip_addr.addr[0]) { + gtway_addr = (uint8_t *)>way_addr_set.ip_addr.addr; + rc = mgmt_modify_gateway(phba, gtway_addr, + IP_ACTION_DEL, IP_V4_LEN); + + if (rc) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to clear Gateway Addr Set\n"); + return rc; + } + } + } + + /* Set Adapter to DHCP/Static Mode */ + if (boot_proto == ISCSI_BOOTPROTO_DHCP) { + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR, + sizeof(*dhcpreq)); + if (rc) + return rc; + + dhcpreq = nonemb_cmd.va; + dhcpreq->flags = BLOCKING; + dhcpreq->retry_count = 1; + dhcpreq->interface_hndl = phba->interface_handle; + dhcpreq->ip_type = BE2_DHCP_V4; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + } else { + return mgmt_static_ip_modify(phba, &if_info, ip_param, + subnet_param, IP_ACTION_ADD); + } + + return rc; +} + +int mgmt_set_gateway(struct beiscsi_hba *phba, + struct iscsi_iface_param_info *gateway_param) +{ + struct be_cmd_get_def_gateway_resp gtway_addr_set; + uint8_t *gtway_addr; + int rt_val; + + memset(>way_addr_set, 0, sizeof(gtway_addr_set)); + rt_val = mgmt_get_gateway(phba, BE2_IPV4, >way_addr_set); + if (rt_val) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to Get Gateway Addr\n"); + return rt_val; + } + + if (gtway_addr_set.ip_addr.addr[0]) { + gtway_addr = (uint8_t *)>way_addr_set.ip_addr.addr; + rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_DEL, + gateway_param->len); + if (rt_val) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to clear Gateway Addr Set\n"); + return rt_val; + } + } + + gtway_addr = (uint8_t *)&gateway_param->value; + rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_ADD, + gateway_param->len); + + if (rt_val) + shost_printk(KERN_WARNING, phba->shost, + "Failed to Set Gateway Addr\n"); + + return rt_val; +} + +int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_def_gateway_resp *gateway) +{ + struct be_cmd_get_def_gateway_req *req; + struct be_dma_mem nonemb_cmd; + int rc; + + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY, + sizeof(*gateway)); + if (rc) + return rc; + + req = nonemb_cmd.va; + req->ip_type = ip_type; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, gateway, + sizeof(*gateway)); +} + +int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_if_info_resp *if_info) +{ + struct be_cmd_get_if_info_req *req; + struct be_dma_mem nonemb_cmd; + int rc; + + if (mgmt_get_all_if_id(phba)) + return -EIO; + + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO, + sizeof(*if_info)); + if (rc) + return rc; + + req = nonemb_cmd.va; + req->interface_hndl = phba->interface_handle; + req->ip_type = ip_type; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, if_info, + sizeof(*if_info)); +} + +int mgmt_get_nic_conf(struct beiscsi_hba *phba, + struct be_cmd_get_nic_conf_resp *nic) +{ + struct be_dma_mem nonemb_cmd; + int rc; + + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, + sizeof(*nic)); + if (rc) + return rc; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, nic, sizeof(*nic)); +} + + + unsigned int be_cmd_get_initname(struct beiscsi_hba *phba) { unsigned int tag = 0; diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 03400f3..5c2e376 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -20,12 +20,16 @@ #ifndef _BEISCSI_MGMT_ #define _BEISCSI_MGMT_ -#include -#include #include #include "be_iscsi.h" #include "be_main.h" +#define IP_ACTION_ADD 0x01 +#define IP_ACTION_DEL 0x02 + +#define IP_V6_LEN 16 +#define IP_V4_LEN 4 + /** * Pseudo amap definition in which each bit of the actual structure is defined * as a byte: used to calculate offset/shift/mask of each field @@ -263,4 +267,27 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short issue_reset, unsigned short savecfg_flag); +int mgmt_set_ip(struct beiscsi_hba *phba, + struct iscsi_iface_param_info *ip_param, + struct iscsi_iface_param_info *subnet_param, + uint32_t boot_proto); + +unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba); + +unsigned int mgmt_get_session_info(struct beiscsi_hba *phba, + u32 boot_session_handle, + struct be_dma_mem *nonemb_cmd); + +int mgmt_get_nic_conf(struct beiscsi_hba *phba, + struct be_cmd_get_nic_conf_resp *mac); + +int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_if_info_resp *if_info); + +int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_def_gateway_resp *gateway); + +int mgmt_set_gateway(struct beiscsi_hba *phba, + struct iscsi_iface_param_info *gateway_param); + #endif -- cgit v0.10.2