From c0b9d3f750520ad3005b99144260e486ef01b5d9 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 13 Feb 2012 18:30:49 +0530 Subject: [SCSI] qla4xxx: Added ping support Added ping support for network connection diagnostics. Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 113 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) (limited to 'drivers/scsi/qla4xxx/ql4_os.c') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index d423f7afbbd7..877c0e220ac9 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -118,6 +118,10 @@ static void qla4xxx_task_cleanup(struct iscsi_task *); static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats); +static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, + uint32_t iface_type, uint32_t payload_size, + uint32_t pid, struct sockaddr *dst_addr); + /* * SCSI host template entry points */ @@ -194,10 +198,91 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .set_iface_param = qla4xxx_iface_set_param, .get_iface_param = qla4xxx_get_iface_param, .bsg_request = qla4xxx_bsg_request, + .send_ping = qla4xxx_send_ping, }; static struct scsi_transport_template *qla4xxx_scsi_transport; +static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, + uint32_t iface_type, uint32_t payload_size, + uint32_t pid, struct sockaddr *dst_addr) +{ + struct scsi_qla_host *ha = to_qla_host(shost); + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + uint32_t options = 0; + uint8_t ipaddr[IPv6_ADDR_LEN]; + int rval; + + memset(ipaddr, 0, IPv6_ADDR_LEN); + /* IPv4 to IPv4 */ + if ((iface_type == ISCSI_IFACE_TYPE_IPV4) && + (dst_addr->sa_family == AF_INET)) { + addr = (struct sockaddr_in *)dst_addr; + memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN); + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 " + "dest: %pI4\n", __func__, + &ha->ip_config.ip_address, ipaddr)); + rval = qla4xxx_ping_iocb(ha, options, payload_size, pid, + ipaddr); + if (rval) + rval = -EINVAL; + } else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) && + (dst_addr->sa_family == AF_INET6)) { + /* IPv6 to IPv6 */ + addr6 = (struct sockaddr_in6 *)dst_addr; + memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN); + + options |= PING_IPV6_PROTOCOL_ENABLE; + + /* Ping using LinkLocal address */ + if ((iface_num == 0) || (iface_num == 1)) { + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping " + "src: %pI6 dest: %pI6\n", __func__, + &ha->ip_config.ipv6_link_local_addr, + ipaddr)); + options |= PING_IPV6_LINKLOCAL_ADDR; + rval = qla4xxx_ping_iocb(ha, options, payload_size, + pid, ipaddr); + } else { + ql4_printk(KERN_WARNING, ha, "%s: iface num = %d " + "not supported\n", __func__, iface_num); + rval = -ENOSYS; + goto exit_send_ping; + } + + /* + * If ping using LinkLocal address fails, try ping using + * IPv6 address + */ + if (rval != QLA_SUCCESS) { + options &= ~PING_IPV6_LINKLOCAL_ADDR; + if (iface_num == 0) { + options |= PING_IPV6_ADDR0; + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " + "Ping src: %pI6 " + "dest: %pI6\n", __func__, + &ha->ip_config.ipv6_addr0, + ipaddr)); + } else if (iface_num == 1) { + options |= PING_IPV6_ADDR1; + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " + "Ping src: %pI6 " + "dest: %pI6\n", __func__, + &ha->ip_config.ipv6_addr1, + ipaddr)); + } + rval = qla4xxx_ping_iocb(ha, options, payload_size, + pid, ipaddr); + if (rval) + rval = -EINVAL; + } + } else + rval = -ENOSYS; +exit_send_ping: + return rval; +} + static umode_t ql4_attr_is_visible(int param_type, int param) { switch (param_type) { @@ -2897,6 +2982,26 @@ int qla4xxx_post_aen_work(struct scsi_qla_host *ha, return QLA_SUCCESS; } +int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, + uint32_t status, uint32_t pid, + uint32_t data_size, uint8_t *data) +{ + struct qla4_work_evt *e; + + e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS); + if (!e) + return QLA_ERROR; + + e->u.ping.status = status; + e->u.ping.pid = pid; + e->u.ping.data_size = data_size; + memcpy(e->u.ping.data, data, data_size); + + qla4xxx_post_work(ha, e); + + return QLA_SUCCESS; +} + void qla4xxx_do_work(struct scsi_qla_host *ha) { struct qla4_work_evt *e, *tmp; @@ -2918,6 +3023,14 @@ void qla4xxx_do_work(struct scsi_qla_host *ha) e->u.aen.data_size, e->u.aen.data); break; + case QLA4_EVENT_PING_STATUS: + iscsi_ping_comp_event(ha->host_no, + &qla4xxx_iscsi_transport, + e->u.ping.status, + e->u.ping.pid, + e->u.ping.data_size, + e->u.ping.data); + break; default: ql4_printk(KERN_WARNING, ha, "event type: 0x%x not " "supported", e->type); -- cgit v1.2.2