diff options
author | Vikas Chaudhary <vikas.chaudhary@qlogic.com> | 2012-02-13 08:00:49 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 10:35:23 -0500 |
commit | c0b9d3f750520ad3005b99144260e486ef01b5d9 (patch) | |
tree | 2c16adb36151017344dea7681e312fb4f68fd3d5 /drivers/scsi/qla4xxx/ql4_os.c | |
parent | ac20c7bf070df2b0feb410558ec4d75dbe59b701 (diff) |
[SCSI] qla4xxx: Added ping support
Added ping support for network connection diagnostics.
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 113 |
1 files changed, 113 insertions, 0 deletions
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 *); | |||
118 | static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); | 118 | static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); |
119 | static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, | 119 | static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, |
120 | struct iscsi_stats *stats); | 120 | struct iscsi_stats *stats); |
121 | static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, | ||
122 | uint32_t iface_type, uint32_t payload_size, | ||
123 | uint32_t pid, struct sockaddr *dst_addr); | ||
124 | |||
121 | /* | 125 | /* |
122 | * SCSI host template entry points | 126 | * SCSI host template entry points |
123 | */ | 127 | */ |
@@ -194,10 +198,91 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { | |||
194 | .set_iface_param = qla4xxx_iface_set_param, | 198 | .set_iface_param = qla4xxx_iface_set_param, |
195 | .get_iface_param = qla4xxx_get_iface_param, | 199 | .get_iface_param = qla4xxx_get_iface_param, |
196 | .bsg_request = qla4xxx_bsg_request, | 200 | .bsg_request = qla4xxx_bsg_request, |
201 | .send_ping = qla4xxx_send_ping, | ||
197 | }; | 202 | }; |
198 | 203 | ||
199 | static struct scsi_transport_template *qla4xxx_scsi_transport; | 204 | static struct scsi_transport_template *qla4xxx_scsi_transport; |
200 | 205 | ||
206 | static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, | ||
207 | uint32_t iface_type, uint32_t payload_size, | ||
208 | uint32_t pid, struct sockaddr *dst_addr) | ||
209 | { | ||
210 | struct scsi_qla_host *ha = to_qla_host(shost); | ||
211 | struct sockaddr_in *addr; | ||
212 | struct sockaddr_in6 *addr6; | ||
213 | uint32_t options = 0; | ||
214 | uint8_t ipaddr[IPv6_ADDR_LEN]; | ||
215 | int rval; | ||
216 | |||
217 | memset(ipaddr, 0, IPv6_ADDR_LEN); | ||
218 | /* IPv4 to IPv4 */ | ||
219 | if ((iface_type == ISCSI_IFACE_TYPE_IPV4) && | ||
220 | (dst_addr->sa_family == AF_INET)) { | ||
221 | addr = (struct sockaddr_in *)dst_addr; | ||
222 | memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN); | ||
223 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 " | ||
224 | "dest: %pI4\n", __func__, | ||
225 | &ha->ip_config.ip_address, ipaddr)); | ||
226 | rval = qla4xxx_ping_iocb(ha, options, payload_size, pid, | ||
227 | ipaddr); | ||
228 | if (rval) | ||
229 | rval = -EINVAL; | ||
230 | } else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) && | ||
231 | (dst_addr->sa_family == AF_INET6)) { | ||
232 | /* IPv6 to IPv6 */ | ||
233 | addr6 = (struct sockaddr_in6 *)dst_addr; | ||
234 | memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN); | ||
235 | |||
236 | options |= PING_IPV6_PROTOCOL_ENABLE; | ||
237 | |||
238 | /* Ping using LinkLocal address */ | ||
239 | if ((iface_num == 0) || (iface_num == 1)) { | ||
240 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping " | ||
241 | "src: %pI6 dest: %pI6\n", __func__, | ||
242 | &ha->ip_config.ipv6_link_local_addr, | ||
243 | ipaddr)); | ||
244 | options |= PING_IPV6_LINKLOCAL_ADDR; | ||
245 | rval = qla4xxx_ping_iocb(ha, options, payload_size, | ||
246 | pid, ipaddr); | ||
247 | } else { | ||
248 | ql4_printk(KERN_WARNING, ha, "%s: iface num = %d " | ||
249 | "not supported\n", __func__, iface_num); | ||
250 | rval = -ENOSYS; | ||
251 | goto exit_send_ping; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * If ping using LinkLocal address fails, try ping using | ||
256 | * IPv6 address | ||
257 | */ | ||
258 | if (rval != QLA_SUCCESS) { | ||
259 | options &= ~PING_IPV6_LINKLOCAL_ADDR; | ||
260 | if (iface_num == 0) { | ||
261 | options |= PING_IPV6_ADDR0; | ||
262 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " | ||
263 | "Ping src: %pI6 " | ||
264 | "dest: %pI6\n", __func__, | ||
265 | &ha->ip_config.ipv6_addr0, | ||
266 | ipaddr)); | ||
267 | } else if (iface_num == 1) { | ||
268 | options |= PING_IPV6_ADDR1; | ||
269 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " | ||
270 | "Ping src: %pI6 " | ||
271 | "dest: %pI6\n", __func__, | ||
272 | &ha->ip_config.ipv6_addr1, | ||
273 | ipaddr)); | ||
274 | } | ||
275 | rval = qla4xxx_ping_iocb(ha, options, payload_size, | ||
276 | pid, ipaddr); | ||
277 | if (rval) | ||
278 | rval = -EINVAL; | ||
279 | } | ||
280 | } else | ||
281 | rval = -ENOSYS; | ||
282 | exit_send_ping: | ||
283 | return rval; | ||
284 | } | ||
285 | |||
201 | static umode_t ql4_attr_is_visible(int param_type, int param) | 286 | static umode_t ql4_attr_is_visible(int param_type, int param) |
202 | { | 287 | { |
203 | switch (param_type) { | 288 | switch (param_type) { |
@@ -2897,6 +2982,26 @@ int qla4xxx_post_aen_work(struct scsi_qla_host *ha, | |||
2897 | return QLA_SUCCESS; | 2982 | return QLA_SUCCESS; |
2898 | } | 2983 | } |
2899 | 2984 | ||
2985 | int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, | ||
2986 | uint32_t status, uint32_t pid, | ||
2987 | uint32_t data_size, uint8_t *data) | ||
2988 | { | ||
2989 | struct qla4_work_evt *e; | ||
2990 | |||
2991 | e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS); | ||
2992 | if (!e) | ||
2993 | return QLA_ERROR; | ||
2994 | |||
2995 | e->u.ping.status = status; | ||
2996 | e->u.ping.pid = pid; | ||
2997 | e->u.ping.data_size = data_size; | ||
2998 | memcpy(e->u.ping.data, data, data_size); | ||
2999 | |||
3000 | qla4xxx_post_work(ha, e); | ||
3001 | |||
3002 | return QLA_SUCCESS; | ||
3003 | } | ||
3004 | |||
2900 | void qla4xxx_do_work(struct scsi_qla_host *ha) | 3005 | void qla4xxx_do_work(struct scsi_qla_host *ha) |
2901 | { | 3006 | { |
2902 | struct qla4_work_evt *e, *tmp; | 3007 | struct qla4_work_evt *e, *tmp; |
@@ -2918,6 +3023,14 @@ void qla4xxx_do_work(struct scsi_qla_host *ha) | |||
2918 | e->u.aen.data_size, | 3023 | e->u.aen.data_size, |
2919 | e->u.aen.data); | 3024 | e->u.aen.data); |
2920 | break; | 3025 | break; |
3026 | case QLA4_EVENT_PING_STATUS: | ||
3027 | iscsi_ping_comp_event(ha->host_no, | ||
3028 | &qla4xxx_iscsi_transport, | ||
3029 | e->u.ping.status, | ||
3030 | e->u.ping.pid, | ||
3031 | e->u.ping.data_size, | ||
3032 | e->u.ping.data); | ||
3033 | break; | ||
2921 | default: | 3034 | default: |
2922 | ql4_printk(KERN_WARNING, ha, "event type: 0x%x not " | 3035 | ql4_printk(KERN_WARNING, ha, "event type: 0x%x not " |
2923 | "supported", e->type); | 3036 | "supported", e->type); |