Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_iscsi_api.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  * Implements the iSCSI API interface functions.
36  */
37 
38 /*!
39 @defgroup iscsi_api iSCSI target/initiator interface
40 */
41 
42 #include "ocs.h"
43 #include "ocs_iscsi_spec.h"
44 #include "ocs_isns.h"
45 
46 #define OCS_ISCSI_API_INIT_DELAY_MS 100
47 
48 static int32_t ocs_iscsi_api_link_configure_thread(ocs_thread_t *mythread);
49 
50 /**
51  * @brief Get a next free sport object index
52  *
53  * @param ocs Pointer to the ocs structure.
54  *
55  * @return Returns sport inx on success.
56  */
57 ocs_sport_t *ocs_iscsi_tgt_get_free_sport(ocs_t *ocs)
58 {
59  ocs_sport_t *sport = NULL;
60  int32_t inx;
61 
62  ocs_domain_lock(ocs->hal.domain);
63  for (inx = 0; inx < OCS_MAX_SPORTS; inx++) {
64  if (ocs->sport[inx].created == FALSE) {
65  sport = &ocs->sport[inx];
66  sport->index = inx;
67  break;
68  }
69  }
70  ocs_domain_unlock(ocs->hal.domain);
71 
72  return sport;
73 }
74 
75 /**
76  * @brief Add sport to iscsi target
77  *
78  * @param ocs Pointer to the ocs structure.
79  * @param scst_tgt Pointer to SCST target
80  * @param sport SPORT that associates SCST target
81  *
82  * @return Returns 0 on success.
83  */
84 int32_t
85 ocs_iscsi_tgt_add_sport(ocs_t *ocs, ocs_sport_t *sport)
86 {
87  int8_t *mac;
89 
90  mac = ocs_hal_get_ptr(&ocs->hal, OCS_HAL_MAC_ADDR);
91  if (mac == NULL) {
92  ocs_log_err(ocs, "HAL mac address get failed\n");
93  return -1;
94  }
95 
96  ocs_domain_lock(ocs->hal.domain);
97 
98  ocs_memcpy(sport->mac, mac,
99  ARRAY_SIZE(sport->mac));
100  ocs_snprintf(sport->mac_str,
101  sizeof(sport->mac_str),
102  "%02x%02x%02x%02x%02x%02x",
103  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
104 
105  sport->domain = ocs->domain;
106  sport->tgt_id = sport->index;
107  sport->created = TRUE;
108  sport->ocs = ocs;
109  sport->mgmt_functions = &sport_mgmt_functions;
110 
111  ocs_sport_lock_init(sport);
112  ocs_list_init(&sport->node_list, ocs_node_t, link);
113  ocs_list_add_tail(&ocs->domain->sport_list, sport);
114 
115  ocs_domain_unlock(ocs->hal.domain);
116 
117  return 0;
118 }
119 
120 /**
121  * @brief Delete sport from iscsi target
122  *
123  * @param ocs Pointer to the ocs structure
124  * @param sport_index SPORT index to be deleted
125  *
126  */
127 void ocs_iscsi_tgt_del_sport(ocs_t *ocs, uint32_t sport_index)
128 {
129  ocs_sport_t *sport;
130  ocs_sport_t *sport_next;
131 
132  ocs_domain_lock(ocs->hal.domain);
133  ocs_list_foreach_safe(&ocs->domain->sport_list, sport,
134  sport_next) {
135  if (sport->index == sport_index && sport->created == TRUE) {
136  sport->created = FALSE;
137  ocs_list_remove(&ocs->domain->sport_list,
138  sport);
139  break;
140  }
141  }
142  ocs_domain_unlock(ocs->hal.domain);
143 }
144 
145 /**
146  * @brief Adds a target.
147  *
148  * @param ocs Pointer to the ocs structure.
149  * @param name Target name.
150  * @param alias Target alias.
151  *
152  * @return Returns 0 on success.
153  */
154 int32_t
155 ocs_iscsi_tgt_add(ocs_t *ocs, char* name, char* alias)
156 {
157  iscsi_api_t *iscsi_api = ocs->iscsi_api;
158  iscsi_api_tgt_t *tgt;
159 
160  tgt = ocs_malloc(ocs, sizeof(iscsi_api_tgt_t), OCS_M_ZERO | OCS_M_NOWAIT);
161  if (tgt == NULL) {
162  ocs_log_err(ocs, "failed to allocate target structure\n");
163  return -1;
164  }
165  ocs_strncpy(tgt->tgt_name, name, ARRAY_SIZE(tgt->tgt_name));
166  ocs_strncpy(tgt->tgt_alias, alias, ARRAY_SIZE(tgt->tgt_alias));
167 
168  ocs_lock(&iscsi_api->api_list_lock);
169  ocs_list_add_tail(&iscsi_api->tgt_list, tgt);
170  ocs_unlock(&iscsi_api->api_list_lock);
171 
172  ocs_log_debug(ocs, "iSCSI target %s created\n", name);
173 
174  return 0;
175 }
176 
177 /**
178  * @brief Returns the target name based on the index.
179  *
180  * @param ocs Pointer to the ocs structure.
181  * @param index Index into the target name list.
182  *
183  * @return Returns pointer to the target name, or NULL if the index exceeds the list.
184  */
185 char *
186 ocs_iscsi_tgt_get_names(ocs_t *ocs, uint32_t index)
187 {
188  iscsi_api_t *iscsi_api = ocs->iscsi_api;
189  iscsi_api_tgt_t *tgt;
190  uint32_t count = 0;
191 
192  ocs_lock(&iscsi_api->api_list_lock);
193  ocs_list_foreach(&iscsi_api->tgt_list, tgt) {
194  if (count == index) {
195  ocs_unlock(&iscsi_api->api_list_lock);
196  return tgt->tgt_name;
197  }
198  count++;
199  }
200  ocs_unlock(&iscsi_api->api_list_lock);
201 
202  return NULL;
203 }
204 
205 
206 /**
207  * @brief Returns the target alias based on the index.
208  *
209  * @param ocs Pointer to the ocs structure.
210  * @param index Index into the target name list.
211  *
212  * @return Returns pointer to the target name, or NULL if the index exceeds the list.
213  */
214 char *
215 ocs_iscsi_tgt_get_alias(ocs_t *ocs, uint32_t index)
216 {
217  iscsi_api_t *iscsi_api = ocs->iscsi_api;
218  iscsi_api_tgt_t *tgt;
219  uint32_t count = 0;
220 
221  ocs_lock(&iscsi_api->api_list_lock);
222  ocs_list_foreach(&iscsi_api->tgt_list, tgt) {
223  if (count == index) {
224  ocs_unlock(&iscsi_api->api_list_lock);
225  return tgt->tgt_alias;
226  }
227  count++;
228  }
229  ocs_unlock(&iscsi_api->api_list_lock);
230  return NULL;
231 }
232 
233 
234 /**
235  * @brief Returns the IP address of the target name based on the index.
236  *
237  * @param ocs Pointer to the ocs structure.
238  * @param tgt_name The iSCSI target name.
239  * @param index Index into the IP Address list.
240  *
241  * @return Pointer to the IP address, or NULL if the index exceeds the list.
242  */
244 ocs_iscsi_tgt_get_ip_address(ocs_t *ocs, char *tgt_name, uint32_t index)
245 {
246  ocs_iscsi_t *iscsi = &ocs->iscsi;
247  ocs_ip_address_t *rc = NULL;
248 
249  /*
250  * Since all the targets share IP addresses, we can skip the target
251  * name and just lookup in the IP Address table.
252  *
253  * Note: Not all IP addresses may be listened on, so we only count
254  * the listening IPs here.
255  */
256  if (index > iscsi->num_ips)
257  return rc;
258 
259  if (iscsi->ip_info[index].listening)
260  rc = &iscsi->ip_info[index].ip;
261 
262  return rc;
263 }
264 
265 
266 /**
267  * @brief Returns the portal group of an IP address of the target name.
268  *
269  * @param ocs Pointer to the ocs structure.
270  * @param tgt_name The iSCSI target name.
271  * @param ip_address IP address.
272  *
273  * @return Returns the target portal group tag.
274  */
275 uint32_t
276 ocs_iscsi_tgt_get_portal_group(ocs_t *ocs, char *tgt_name, ocs_ip_address_t *ip_address)
277 {
278  /* Always use group 1 since sessions can span the addresses we use */
279  return 1;
280 }
281 
282 
283 /**
284  * @brief Returns TRUE if CHAP is required for the session type.
285  *
286  * @param ocs Pointer to the ocs structure.
287  * @param tgt_name The iSCSI target name.
288  * @param type Either discovery or normal sessions.
289  *
290  * @return Returns TRUE if CHAP is required.
291  */
292 uint8_t
293 ocs_iscsi_tgt_require_chap(ocs_t *ocs, char *tgt_name, ocs_session_type_e type)
294 {
295  /* Do not require CHAP */
296  return ocs->require_chap;
297 }
298 
299 
300 /**
301  * @brief Checks if this initiator is allowed access to a target.
302  *
303  * @param ocs Pointer to the ocs structure.
304  * @param tgt_name The iSCSI target name.
305  * @param ini_name The iSCSI initiator name.
306  *
307  * @return Returns TRUE if access is allowed.
308  */
309 uint32_t
310 ocs_iscsi_tgt_is_access_allowed(ocs_t *ocs, char *tgt_name, char *ini_name)
311 {
312  /* Always allow access */
313  return TRUE;
314 }
315 
316 
317 /**
318  * @brief Return this initiator's name.
319  *
320  * @param ocs Pointer to the ocs structure.
321  *
322  * @return Pointer to the initiator name.
323  */
324 char *
326 {
327  iscsi_api_t *iscsi_api = ocs->iscsi_api;
328  uint8_t *mac;
329 
330  mac = ocs_hal_get_ptr(&ocs->hal, OCS_HAL_MAC_ADDR);
331 
332  snprintf(iscsi_api->ini_name,
334  "%s:%02x%02x%02x%02x%02x%02x",
335  ocs->iqn_prefix,
336  mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
337 
338  return iscsi_api->ini_name;
339 }
340 
341 
342 /**
343  * @brief Returns the initiator alias
344  *
345  * @param ocs Pointer to the ocs structure
346  *
347  * @return Pointer to the initiator alias or NULL
348  */
349 char *
351 {
352  return "emulex:ini";
353 }
354 
355 
356 /**
357  * @brief Initialize the higher level iSCSI software
358  *
359  * @param ocs Pointer to the ocs structure
360  *
361  * @return 0 for success
362  */
363 int32_t
365 {
366  ocs_ip_address_t ip;
367  ocs_ip_address_t subnet;
368  iscsi_api_t *iscsi_api;
369  int32_t rc;
370 
371  ocs->iscsi_api = ocs_malloc(ocs, sizeof(iscsi_api_t),
372  OCS_M_ZERO | OCS_M_NOWAIT);
373  if (ocs->iscsi_api == NULL) {
374  ocs_log_err(ocs, "failed to allocate iscsi_api structure\n");
375  return -1;
376  }
377 
378  iscsi_api = ocs->iscsi_api;
379 
380  ocs_lock_init(ocs, &iscsi_api->api_list_lock, "iscsi API list lock");
381  ocs_list_init(&iscsi_api->tgt_list, ocs_chap_user_t, link);
382  ocs_list_init(&iscsi_api->chap_list, ocs_chap_user_t, link);
384 
385  ocs_sem_init(&iscsi_api->link_cfg_sem, 0, "link cfg sem");
386 
387  /* Convert the supplied local IP Address */
388  if(ocs_strcmp(ocs->local_ip, "MGMT") == 0) {
389  iscsi_api->enable_mgmt_flag = 1;
390  } else if (ocs_strcmp(ocs->local_ip, "DHCP") == 0) {
391  iscsi_api->ipsub.ip_type = OCS_IP_TYPE_DHCP_V4;
392  } else if (ocs_strcmp(ocs->local_ip, "AutoV6") == 0) {
393  iscsi_api->ipsub.ip_type = OCS_IP_TYPE_AUTO_V6;
394  } else if (ocs_iscsi_inet_pton4(ocs->local_ip, &ip) == 0) {
395  /* Convert the subnet */
396  if (ocs_iscsi_inet_pton4(ocs->local_subnet, &subnet) == 0) {
397  ocs_iscsi_ipsub_combine(&iscsi_api->ipsub, &ip, &subnet);
398  } else {
399  ocs_log_err(ocs, "IPv4 address supplied, but subnet is not an valid IPv4 subnet\n");
400  ocs_free(ocs, iscsi_api, sizeof(iscsi_api_t));
401  return -1;
402  }
403 
404  /* Convert the gateway */
405  if (ocs_iscsi_inet_pton4(ocs->gateway, &ip) == 0) {
406  iscsi_api->set_gateway = TRUE;
407  iscsi_api->gateway = ip;
408  }
409  } else if (ocs_iscsi_inet_pton6(ocs->local_ip, &ip) == 0) {
410  if (ocs_iscsi_inet_pton6(ocs->local_subnet, &subnet) == 0) {
411  ocs_iscsi_ipsub_combine(&iscsi_api->ipsub, &ip, &subnet);
412  } else {
413  ocs_log_err(ocs, "IPv6 address supplied, but subnet is not an valid IPv6 subnet\n");
414  ocs_free(ocs, iscsi_api, sizeof(iscsi_api_t));
415  return -1;
416  }
417 
418  /* Convert the gateway */
419  if (ocs_iscsi_inet_pton6(ocs->gateway, &ip) == 0) {
420  iscsi_api->set_gateway = TRUE;
421  iscsi_api->gateway = ip;
422  }
423  } else {
424  ocs_log_err(ocs, "ERROR: Local address supplied is not a valid IPv4, IPv6, DHCP, AutoV6, or MGMT\n");
425  ocs_free(ocs, iscsi_api, sizeof(iscsi_api_t));
426  return -1;
427  }
428 
429  /* Adjust static IP addresses based on the pci function */
430  if (iscsi_api->ipsub.ip_type == OCS_IP_TYPE_V4) {
431  iscsi_api->ipsub.ip_address[3] += ocs->instance_index;
432  } else if (iscsi_api->ipsub.ip_type == OCS_IP_TYPE_V6) {
433  iscsi_api->ipsub.ip_address[15] += ocs->instance_index;
434  }
435 
436  /* Register to received link state change events */
438  if (rc != 0) {
439  ocs_log_err(ocs, "Failed to register a link state callback function\n");
440  }
441 
442  /*
443  * Start a thread to configure the link as we cannot call the API
444  * functions from an interrupt context.
445  */
446  rc = ocs_thread_create(ocs, &iscsi_api->link_cfg_thread,
448  "Link cfg thread",
449  ocs,
450  OCS_THREAD_RUN);
451  if (rc != 0) {
452  ocs_log_err(ocs, "Link config thread start returned %d\n", rc);
453  } else {
454  iscsi_api->cfg_thread_started = TRUE;
455  }
456 
457  return rc;
458 }
459 
460 
461 /**
462  * @brief Initialize the higher level iSCSI software
463  *
464  * @param ocs Pointer to the ocs structure
465  *
466  * @return 0 for success
467  */
468 int32_t
470 {
471  ocs_iscsi_t *iscsi = &ocs->iscsi;
472  iscsi_api_t *iscsi_api = ocs->iscsi_api;
473  iscsi_api_tgt_t *tgt;
474  ocs_vlan_portal_info_t *portal_info;
475  ocs_vlan_portal_info_t *portal_next;
477  uint32_t i;
478  uint32_t num_ips;
479  int32_t rc = 0;
480  char ip_str[40];
481 
482  if (ocs->iscsi_api == NULL) {
483  /* We never got initialized */
484  return 0;
485  }
486 
487  /* Cleanup the target list */
488  ocs_lock(&iscsi_api->api_list_lock);
489  while ((tgt = ocs_list_remove_head(&iscsi_api->tgt_list)) != NULL) {
490  ocs_free(ocs, tgt, sizeof(iscsi_api_tgt_t));
491  }
492 
493  /* Cleanup the CHAP secret list */
494  while ((chap = ocs_list_remove_head(&iscsi_api->chap_list)) != NULL) {
495  ocs_free(ocs, chap, sizeof(ocs_chap_user_t));
496  }
497  ocs_unlock(&iscsi_api->api_list_lock);
498 
499  /* Wake up the configure thread */
500  if (iscsi_api->cfg_thread_started) {
501  if (ocs_thread_terminate(&iscsi_api->link_cfg_thread) != 0) {
502  ocs_log_test(ocs, "Error stopping Link config thread\n");
503  }
504  ocs_sem_v(&iscsi_api->link_cfg_sem);
505  }
506 
507  if (iscsi_api->link_configured) {
508  num_ips = iscsi->num_ips;
509  i = 0;
510  while (i < num_ips) {
511  rc = 0;
513  iscsi->ip_info[i].ip.ip_address,
514  ip_str, sizeof(ip_str));
515 
516  /* Stop listening on the ip addresses */
517  if (iscsi->ip_info[i].listening) {
518  if ((rc = ocs_iscsi_listen_stop(ocs,
519  &iscsi->ip_info[i].ip,
520  iscsi->ip_info[i].tcp_port))) {
521  ocs_log_test(ocs, "failed Stopping Listen on IP %s\n",
522  ip_str);
523  } else {
524  ocs_log_debug(ocs, "Stopped Listening on IP %s\n", ip_str);
525  }
526  }
527 
528  if (iscsi->ip_info[i].esi_listening) {
529  if ((rc = ocs_iscsi_isns_esi_listen_stop(ocs,
530  &iscsi->ip_info[i].ip,
531  iscsi->ip_info[i].esi_port))) {
532  ocs_log_test(ocs, "failed Stopping ESI Listen on IP %s\n",
533  ip_str);
534  } else {
535  ocs_log_debug(ocs, "Stopped ESI Listening on IP %s\n",
536  ip_str);
537  }
538  }
539 
540  if (iscsi_api->isns_registered) {
541  if (ocs_isns_deregister(ocs, iscsi_api->isns_servers, iscsi_api->isns_eid) == 0) {
542  ocs_log_debug(ocs,"iSNS deregistration done successfully!\n");
543  } else {
544  ocs_log_test(ocs,"ERROR: iSNS deregistration FAILED!\n");
545  }
546  }
547 
548  /* Remove any IP addresses added */
549  if (iscsi->ip_info[i].ip_added) {
551 
553  &iscsi->ip_info[i].ip,
554  &iscsi->ip_info[i].subnet);
555  if ((rc = ocs_iscsi_ip_address_remove(ocs,
556  iscsi->ip_info[i].portal,
557  &ipsub))) {
558  ocs_log_test(ocs, "failed removing IP address %s\n", ip_str);
559  } else {
560  ocs_log_debug(ocs, "removed IP address %s\n", ip_str);
561  }
562  }
563 
564  /* Check if ip_info entry cleanup failed, then move to next entry */
565  if (rc) {
566  i++;
567  }
568 
569  /* Update num_ips after each entry removal */
570  num_ips = iscsi->num_ips;
571  } /* while end */
572  }
573 
574  /* Cleanup the portal list */
575  ocs_list_foreach_safe(&iscsi_api->portal_list, portal_info, portal_next) {
576  rc = ocs_iscsi_portal_delete(ocs, portal_info->iface_handle);
577  if (rc){
578  ocs_log_err(ocs, "Delete IFACE handle %d failed\n",
579  portal_info->iface_handle);
580  } else {
581  ocs_log_debug(ocs, "Deleted IFACE handle %d of vlan_id %d\n",
582  portal_info->iface_handle, portal_info->vlan_id);
583  ocs_list_remove(&iscsi_api->portal_list, portal_info);
584  ocs_free(ocs, portal_info, sizeof(*portal_info));
585  }
586  }
587 
588  ocs_lock_free(&iscsi_api->api_list_lock);
589 
590  if (iscsi_api->isns_servers != NULL) {
591  ocs_free(ocs, iscsi_api->isns_servers, sizeof(ocs_ip_address_t) * OCS_MAX_IP);
592  iscsi_api->isns_servers = NULL;
593  }
594 
595  ocs_free(ocs, iscsi_api, sizeof(iscsi_api_t));
596  ocs->iscsi_api = NULL;
597 
598  return rc;
599 }
600 
601 
602 /**
603  * @brief Checks to see if the target name is this target
604  *
605  * @param ocs Pointer to the ocs structure
606  * @param remote_name Pointer to the target name
607  *
608  * @return 0 if this is a local target, 1 if is not a local target
609  */
610 static uint8_t
611 ocs_iscsi_api_not_local_target(ocs_t *ocs, char *remote_name)
612 {
613  uint16_t ctr = 0;
614  char *my_name;
615 
616  my_name = ocs_iscsi_tgt_get_names(ocs, ctr);
617  while(my_name){
618  if(ocs_strcmp(my_name, remote_name)){
619  ocs_log_debug(ocs, "(%d) different: (%s) and (%s)\n", (int) ctr, my_name, remote_name);
620  ctr++;
621  my_name = ocs_iscsi_tgt_get_names(ocs, ctr);
622  }
623  else{
624  ocs_log_debug(ocs, "(%d) same: (%s) and (%s)\n", (int) ctr, my_name, remote_name);
625  return 0;
626  }
627  }
628  return 1;
629 }
630 
631 /**
632  * @brief Logs into any remote targets discovered through iSNS that are not this
633  * device.
634  *
635  * @param ocs Pointer to the ocs structure
636  * @param ret Pointer from the iSNS query
637  * @param nodes_count The number of nodes discovered
638  */
639 static void
640 ocs_iscsi_api_isns_connect(ocs_t *ocs, void *ret, uint16_t nodes_count)
641 {
642  ocs_ip_address_t remote_ip;
643  ocs_hal_ip_address_t hal_ip;
644  int32_t rc = 0;
645  uint16_t i;
646  uint16_t port;
647  char *iscsi_name;
648  char *ip_string;
649 
650  for(i = 0; i < nodes_count; i++){
651  iscsi_name = ocs_get_iscsi_name(&ocs->iscsi, ret, i);
652  if(ocs_iscsi_api_not_local_target(ocs, iscsi_name)){
653  ip_string = ocs_get_ip(&ocs->iscsi, ret, i, 0);
654  ocs_str_to_ip_struct(&ocs->iscsi, ip_string, &remote_ip);
655  port = ocs_get_port(&ocs->iscsi, ret, i, 0);
656  ocs_iscsi_convert_to_hal_ip(&remote_ip, &hal_ip);
657  rc |= ocs_cxn_connect(&ocs->iscsi,
658  &hal_ip,
659  port,
660  iscsi_name);
661  if (rc){
662  ocs_log_test(ocs, "Failed to connect to target %s\n", iscsi_name);
663  } else {
664  ocs_log_debug(ocs, "connecting to target %s\n", iscsi_name);
665  }
666  }
667  }
668  return;
669 }
670 
671 /**
672  * @brief Register/query the iSNS server.
673  *
674  * @param ocs Pointer to the ocs structure
675  * @param portal The portal to use for iSNS
676  * @param isns_servers The table allocated to query the iSNS addresses
677  */
678 static void
680  ocs_hal_portal_t portal,
681  ocs_ip_address_t *isns_servers)
682 {
683  ocs_iscsi_t *iscsi = &ocs->iscsi;
684  iscsi_api_t *iscsi_api = ocs->iscsi_api;
685  int32_t rc;
686  uint32_t num_ips, i;
687  char ip_str[40];
688  uint16_t nodes_count = 0;
689  void *qry_rsp_ptr = NULL;
690 
691  rc = ocs_iscsi_isns_discover(ocs, portal, OCS_MAX_IP,
692  &num_ips, isns_servers);
693  if (rc == 0) {
694  ocs_log_debug(ocs, "iSNS Discovery succeeded, servers found %d\n",
695  num_ips);
696  for (i = 0; i < num_ips; i++) {
697  format_ip_address(isns_servers[i].ip_type,
698  isns_servers[i].ip_address,
699  ip_str, sizeof(ip_str));
700  ocs_log_debug(ocs, "iSNS server found at %s\n", ip_str);
701 
702  if (ocs->enable_tgt || ocs->enable_ini) {
703  if(ocs_isns_register(&ocs->iscsi, ocs->enable_tgt, ocs->enable_ini, &isns_servers[i], iscsi_api->isns_eid) == 0){
704  iscsi_api->isns_registered = TRUE;
705  }
706  else{
707  ocs_log_test(ocs, "ISNS REGISTERATION FAILED!\n");
708  }
709  }
710  if (ocs->enable_ini && iscsi_api->isns_registered) {
711  /*query the registered targets*/
712  qry_rsp_ptr = ocs_isns_qry_tgts(&ocs->iscsi, &isns_servers[i], &nodes_count);
713  if(nodes_count == 0){
714  ocs_log_test(ocs, "iSNS ERROR: the number of discovered nodes = 0\n");
715  } else if (qry_rsp_ptr != NULL) {
716  ocs_iscsi_api_isns_connect(ocs, qry_rsp_ptr, nodes_count);
717  } else {
718  ocs_log_test(ocs, "ISNS TARGETS QUERY FAILED!\n");
719  }
720  ocs_free(ocs, qry_rsp_ptr, nodes_count * sizeof(ocs_isns_node_t));
721  }
722  }
723  } else {
724  ocs_log_test(ocs, "iSNS Discovery status %d\n", rc);
725  }
726 
727  if (iscsi_api->isns_registered) {
728  for (i = 0; i < iscsi->num_ips; i++) {
729  if (iscsi->ip_info[i].ip.ip_type == OCS_IP_TYPE_DHCP_V4) {
731  iscsi->ip_info[i].ip.ip_address,
732  ip_str, sizeof(ip_str));
733 
734  /* Start the ESI listen socket - needs to be on the DHCP address */
736  &iscsi->ip_info[i].ip,
737  ISNS_ESI_PORT) == 0) {
738  ocs_log_debug(ocs, "Start iSNS ESI listen on IP %s\n", ip_str);
739  iscsi->ip_info[i].esi_listening = 1;
740  iscsi->ip_info[i].esi_port = ISNS_ESI_PORT;
741  } else {
742  ocs_log_test(ocs, "failed to start iSNS ESI listen on IP %s\n",
743  ip_str);
744  }
745  }
746  }
747  }
748 }
749 
750 static void ocs_iscsi_api_non_mgmt_config(ocs_t *ocs, ocs_hal_portal_t portal)
751 {
752  uint32_t ip_found;
753  uint32_t i;
754  uint32_t rc;
755  ocs_iscsi_t *iscsi = &ocs->iscsi;
756  iscsi_api_t *iscsi_api = ocs->iscsi_api;
757  char ip_str[40];
758 
759  if (iscsi_api->isns_servers == NULL) {
760  iscsi_api->isns_servers = ocs_malloc(ocs, sizeof(ocs_ip_address_t) * OCS_MAX_IP, OCS_M_ZERO | OCS_M_NOWAIT);
761  }
762 
763  if (iscsi_api->isns_servers == NULL) {
764  ocs_log_err(ocs, "unable to allocate ip temporary variables\n");
765  return;
766  }
767 
768  /* See if our IP address is present, if so, then skip */
769  ip_found = ocs_iscsi_is_ip_in_tbl(ocs, &iscsi_api->ipsub);
770  if (!ip_found) {
771  rc = ocs_iscsi_ip_address_add(ocs, portal, &iscsi_api->ipsub);
772  if (rc == 0) {
773  /*
774  * In the case of auto addresses, it may already be
775  * present, so we need to check before adding it to
776  * the table.
777  */
778  ip_found = ocs_iscsi_is_ip_in_tbl(ocs, &iscsi_api->ipsub);
779  if (!ip_found) {
781  (ocs, "Added", &iscsi_api->ipsub, portal);
782  }
783  } else {
784  ocs_log_test(ocs, "add IP returned status %d\n", rc);
785  }
786  }
787 
788  if (iscsi_api->set_gateway) {
789  rc = ocs_iscsi_gateway_set(ocs, &iscsi_api->gateway);
790  if (rc == 0) {
791  format_ip_address(iscsi_api->gateway.ip_type,
792  iscsi_api->gateway.ip_address,
793  ip_str, sizeof(ip_str));
794  ocs_log_debug(ocs, "Added Gateway address %s\n", ip_str);
795  } else {
796  ocs_log_test(ocs, "setting gateway returned status %d\n", rc);
797  }
798  }
799 
800  /* Start the listen server for targets */
801  if (ocs->enable_tgt) {
802  for (i = 0; i < iscsi->num_ips; i++) {
804  iscsi->ip_info[i].ip.ip_address,
805  ip_str, sizeof(ip_str));
806 
807  iscsi->ip_info[i].tcp_port = OCS_ISCSI_TCP_PORT;
808  rc = ocs_iscsi_listen_start(ocs,
809  &iscsi->ip_info[i].ip,
810  iscsi->ip_info[i].tcp_port);
811  if (rc == 0) {
812  ocs_log_debug(ocs, "Listen server started on %s\n",
813  ip_str);
814  iscsi->ip_info[i].listening = 1;
815  } else {
816  ocs_log_test(ocs, "listen returned status %d on %s\n",
817  rc, ip_str);
818  }
819  }
820  }
821 
822  /* try to find the iSNS server */
823  if ((ocs->ctrlmask & OCS_CTRLMASK_ISCSI_ISNS_ENABLE) != 0) {
824  ocs_iscsi_isns_configure(ocs, portal, iscsi_api->isns_servers);
825  }
826 }
827 
828 
829 /**
830  * @brief Configures the link on initial link up.
831  *
832  * @param ocs Pointer to the ocs structure
833  */
834 static void
836 {
837  ocs_hal_portal_t portal;
838  int32_t rc;
839  uint32_t num_ips;
840  ocs_ip_address_subnet_t *ipsub_tbl;
841  ocs_ip_type_e ip_type;
842  uint32_t i;
843 
844  ipsub_tbl = ocs_malloc(ocs, sizeof(ocs_ip_address_subnet_t) * OCS_MAX_IP, OCS_M_ZERO | OCS_M_NOWAIT);
845  if(ipsub_tbl == NULL){
846  ocs_log_err(ocs, "unable to allocate ip temporary variables\n");
847  ocs_free(ocs, ipsub_tbl, sizeof(ocs_ip_address_subnet_t) * OCS_MAX_IP);
848  return;
849  }
850 
851  portal = ocs_iscsi_portal_get_default(ocs);
852  ocs_log_debug(ocs, "Default portal %d\n", portal);
853 
854  rc = ocs_iscsi_mtu_set(ocs, ocs->enable_jumbo_frame);
855  if (rc ==0) {
856  ocs_log_debug(ocs, "set MTU to %s\n",
857  (ocs->enable_jumbo_frame == TRUE ? "Jumbo" : "Standard"));
858  } else {
859  ocs_log_test(ocs, "Failed setting MTU, status=%d\n", rc);
860  }
861 
862  /*
863  * Initiator and target functions share IP addresses. So query the FW
864  * to see if any addresses are set. We have to query IPv4 and IPv6
865  * separately.
866  */
867  ip_type = OCS_IP_TYPE_V4;
868  do {
870  portal,
871  ip_type,
872  OCS_MAX_IP,
873  &num_ips,
874  ipsub_tbl);
875  if (rc == 0) {
876  /* add to IP table */
877  for (i = 0; i < num_ips; i++) {
878  /*
879  * If we found a DHCP address and we are doing
880  * DHCP, wait, because the address may change.
881  * Let the protocol proceed and see if we renew.
882  */
883  if (ipsub_tbl[i].ip_type == OCS_IP_TYPE_DHCP_V4 ||
884  ipsub_tbl[i].ip_type == OCS_IP_TYPE_AUTO_V6) {
885  continue;
886  }
887 
889  (ocs,
890  "Found",
891  &ipsub_tbl[i],
892  portal);
893  }
894  } else {
895  ocs_log_test(ocs, "Query IP returned status %d\n", rc);
896  }
897  if (ip_type == OCS_IP_TYPE_V4) {
898  ip_type = OCS_IP_TYPE_V6;
899  } else {
900  break;
901  }
902  } while(1);
903 
904  if(ocs->iscsi_api->enable_mgmt_flag) {
905  ocs_log_debug(ocs, "waiting for ip managment configuration\n");
906  } else if(rc == 0){
907  ocs_iscsi_api_non_mgmt_config(ocs, portal);
908  }
909 
910  ocs_free(ocs, ipsub_tbl, sizeof(ocs_ip_address_subnet_t) * OCS_MAX_IP);
911  return;
912 }
913 
914 
915 /**
916  * @brief Configures the link on initial link up.
917  *
918  * @param mythread pointer to thread object
919  */
920 static int32_t
921 ocs_iscsi_api_link_configure_thread(ocs_thread_t *mythread)
922 {
923  ocs_t *ocs = mythread->arg;
924  ocs_iscsi_t *iscsi = &ocs->iscsi;
925  iscsi_api_t *iscsi_api = ocs->iscsi_api;
926  int32_t rc;
927 
928  while (ocs_thread_terminate_requested(mythread) == 0) {
929  rc = ocs_sem_p(&iscsi_api->link_cfg_sem, 100000);
930 
931  if (rc == 0) {
932  if (!iscsi_api->link_configured) {
933  /* wait for initialization to complete */
934  while (!iscsi->is_init_complete) {
935  ocs_msleep(OCS_ISCSI_API_INIT_DELAY_MS);
936  }
937  iscsi_api->link_configured = TRUE;
939  }
940  }
941  }
942  ocs_log_debug(ocs, "link configuration thread exiting\n");
943  return 0;
944 }
945 
946 /**
947  * @brief Notifies the higher level iSCSI software of the link state
948  *
949  * @param ocs Pointer to the ocs structure
950  * @param link_state Provides the status of the link
951  */
952 void
954 {
955  iscsi_api_t *iscsi_api = ocs->iscsi_api;
956 
957  if (link_state == OCS_LINK_STATE_UP) {
958  ocs_sem_v(&iscsi_api->link_cfg_sem);
959  }
960 }
961 
962 /**
963  * @brief Returns the maximum number of connections allowed per session.
964  *
965  * @param ocs Pointer to the ocs structure
966  * @param tgt_name The iSCSI target name
967  * @param ini_name The iSCSI initiator name
968  */
969 uint32_t
970 ocs_iscsi_get_max_cxns(ocs_t *ocs, char *tgt_name, char *ini_name)
971 {
972  return ocs->max_cxns_per_session;
973 }
974 
975 /**
976  * @brief Returns the CHAP user name of corresponding type
977  *
978  * @param ocs Pointer to the ocs structure
979  * @param sess_type Either discovery or nomal session
980  * @param mode Username for Target mode or Initaitor mode
981  * @param type CHAP incoming or outgoing
982  */
983 char *ocs_iscsi_get_chap_name(ocs_t *ocs, uint8_t sess_type,
984  uint32_t mode, uint32_t type)
985 {
986  iscsi_api_t *iscsi_api = ocs->iscsi_api;
988 
989  ocs_lock(&iscsi_api->api_list_lock);
990  ocs_list_foreach(&iscsi_api->chap_list, chap) {
991  if ((chap->mode == mode) && (chap->type == type)) {
992  ocs_unlock(&iscsi_api->api_list_lock);
993  return chap->username;
994  }
995  }
996  ocs_unlock(&iscsi_api->api_list_lock);
997 
998  return NULL;
999 }
1000 
1001 /**
1002  * @brief Returns the unenctypted CHAP secret for a specific user name.
1003  * Note: Passwords should be at least 16 characters.
1004  *
1005  * @param ocs Pointer to the ocs structure
1006  * @param name Username to which the secret to be identified
1007  * @param secret_len Length of the secret code
1008  */
1009 char *ocs_iscsi_get_chap_secret(ocs_t *ocs, char *name, uint32_t mode,
1010  uint32_t type, uint32_t *secret_len)
1011 {
1012  iscsi_api_t *iscsi_api = ocs->iscsi_api;
1014 
1015  ocs_lock(&iscsi_api->api_list_lock);
1016  ocs_list_foreach(&iscsi_api->chap_list, chap) {
1017  if ((chap->mode == mode) && (chap->type == type)) {
1018  if (ocs_strcmp(name, chap->username) == 0) {
1019  *secret_len = ocs_strlen(chap->secret);
1020  ocs_unlock(&iscsi_api->api_list_lock);
1021  return chap->secret;
1022  }
1023  }
1024  }
1025 
1026  ocs_unlock(&iscsi_api->api_list_lock);
1027  *secret_len = 0;
1028  return NULL;
1029 }
1030 
1031 /**
1032  * @brief Add CHAP user.
1033  * If CHAP user of same type is already exists, return error.
1034  *
1035  * @param ocs Pointer to the ocs structure
1036  * @param username Username to add
1037  * @param secret Secret to add
1038  * @param type CHAP type is incoming or outgoing
1039  * @param mode Target or Initiator mode
1040  *
1041  * Return zero on success, otherwise a negative value
1042  */
1043 int32_t ocs_iscsi_chap_user_add(ocs_t *ocs, char *username,
1044  char *secret, uint32_t type, uint32_t mode)
1045 {
1046  iscsi_api_t *iscsi_api = ocs->iscsi_api;
1048  uint8_t found = FALSE;
1049  int32_t rc = -1;
1050 
1051  ocs_lock(&iscsi_api->api_list_lock);
1052 
1053  /* Check for duplicates */
1054  ocs_list_foreach(&iscsi_api->chap_list, chap) {
1055  if ((mode == chap->mode) && (type == chap->type)) {
1056  found = TRUE;
1057  break;
1058  }
1059  }
1060 
1061  if (!found) {
1062  chap = ocs_malloc(ocs, sizeof(ocs_chap_user_t),
1063  OCS_M_ZERO | OCS_M_NOWAIT);
1064  if (chap != NULL) {
1065  ocs_strcpy(chap->username, username);
1066  ocs_strcpy(chap->secret, secret);
1067  chap->type = type;
1068  chap->mode = mode;
1069  ocs_list_add_tail(&iscsi_api->chap_list, chap);
1070  rc = 0;
1071  ocs_log_debug(ocs, "%s CHAP %s:%s is added for %s\n",
1072  (type == OCS_CHAP_TYPE_INCOMING) ? "Incoming": "Outgoing",
1073  username, secret,
1074  (mode == OCS_CHAP_MODE_TARGET) ? "Target" : "Initiator");
1075  }
1076  } else {
1077  ocs_log_info(ocs, "CHAP type %s is already exists\n",
1078  (type == OCS_CHAP_TYPE_INCOMING) ? "Incoming" : "Outgoing");
1079  }
1080 
1081  ocs_unlock(&iscsi_api->api_list_lock);
1082  return rc;
1083 }
1084 
1085 /**
1086  * @brief Delete CHAP user.
1087  *
1088  * @param ocs Pointer to the ocs structure
1089  * @param username Username to delete
1090  * @param type CHAP type is incoming or outgoing
1091  * @param mode Target or Initiator mode
1092  *
1093  * Return zero on success, otherwise a negative value
1094  */
1095 int32_t ocs_iscsi_chap_user_del(ocs_t *ocs, char *username, uint32_t type, uint32_t mode)
1096 {
1097  iscsi_api_t *iscsi_api = ocs->iscsi_api;
1099  ocs_chap_user_t *chap_next;
1100  int32_t rc = -1;
1101 
1102  if (ocs->require_chap) {
1103  ocs_log_info(ocs, "CHAP is enabled! Deletion is not allowed\n");
1104  return rc;
1105  }
1106 
1107  ocs_lock(&iscsi_api->api_list_lock);
1108 
1109  /*
1110  * Restrict deleting CHAP type incoming prior to the type outgoing.
1111  * No use case to support only the type outgoing.
1112  */
1113  if (type == OCS_CHAP_TYPE_INCOMING) {
1114  ocs_list_foreach_safe(&iscsi_api->chap_list, chap, chap_next) {
1115  /* If CHAP outgoing found, then just return failure */
1116  if (chap->type == OCS_CHAP_TYPE_OUTGOING) {
1117  ocs_log_err(ocs, "CHAP type outgoing must be deleted "
1118  "prior to the type incoming.\n");
1119  ocs_unlock(&iscsi_api->api_list_lock);
1120  goto exit_err;
1121  }
1122  }
1123  }
1124 
1125  /* Find a match */
1126  ocs_list_foreach_safe(&iscsi_api->chap_list, chap, chap_next) {
1127  if ((mode == chap->mode) && (type == chap->type)) {
1128  if (ocs_strcmp(username, chap->username) == 0) {
1129  ocs_list_remove(&iscsi_api->chap_list, chap);
1130  ocs_free(ocs, chap, sizeof(ocs_chap_user_t));
1131  ocs_log_debug(ocs, "%s CHAP %s:%s is removed for %s\n",
1132  (type == OCS_CHAP_TYPE_INCOMING) ? "Incoming": "Outgoing",
1133  username, chap->secret,
1134  (mode == OCS_CHAP_MODE_TARGET) ? "Target" : "Initiator");
1135  rc = 0;
1136  break;
1137  }
1138  }
1139  }
1140  ocs_unlock(&iscsi_api->api_list_lock);
1141 
1142  if (rc) {
1143  ocs_log_info(ocs, "CHAP user %s of type %s is not found\n",
1144  username,
1145  (type == OCS_CHAP_TYPE_INCOMING) ? "Incoming": "Outgoing");
1146  }
1147 
1148 exit_err:
1149  return rc;
1150 }
1151 
1152 /**
1153  * @brief Returns the count of chap_list.
1154  */
1155 int32_t ocs_iscsi_chap_list_count(ocs_t *ocs)
1156 {
1157  iscsi_api_t *iscsi_api = ocs->iscsi_api;
1159  ocs_chap_user_t *chap_next;
1160  int32_t cnt = 0;
1161 
1162  ocs_lock(&iscsi_api->api_list_lock);
1163  ocs_list_foreach_safe(&iscsi_api->chap_list, chap, chap_next) {
1164  cnt++;
1165  }
1166  ocs_unlock(&iscsi_api->api_list_lock);
1167 
1168  return cnt;
1169 }
1170 
1171 /**
1172  * @brief Return CHAP list items
1173  *
1174  * @param ocs OCS context
1175  * @param userbuf User buffer to which chap_list items are copied
1176  * @param buflen User buffer length
1177  *
1178  * @Return zero on success, otherwise a negative value
1179  */
1180 int32_t ocs_iscsi_chap_list_get(ocs_t *ocs, char *userbuf, int32_t buflen)
1181 {
1182  iscsi_api_t *iscsi_api = ocs->iscsi_api;
1184  ocs_chap_user_t *chap_next;
1185  ocs_chap_user_buffer_t chap_user_buff;
1186  int32_t offset = 0;
1187 
1188  ocs_lock(&iscsi_api->api_list_lock);
1189  ocs_list_foreach_safe(&iscsi_api->chap_list, chap, chap_next) {
1190  if (offset >= buflen) {
1191  ocs_log_err(ocs, "User buffer is insufficient\n");
1192  ocs_unlock(&iscsi_api->api_list_lock);
1193  return -EFAULT;
1194  }
1195 
1196  ocs_memset(&chap_user_buff, 0, sizeof(ocs_chap_user_buffer_t));
1197  ocs_strncpy(chap_user_buff.username, chap->username,
1198  sizeof(chap_user_buff.username));
1199  ocs_strncpy(chap_user_buff.secret, chap->secret,
1200  sizeof(chap_user_buff.secret));
1201  chap_user_buff.type = chap->type;
1202  chap_user_buff.mode = chap->mode;
1203 
1204  if (ocs_copy_to_user(userbuf + offset, &chap_user_buff,
1205  sizeof(ocs_chap_user_buffer_t))) {
1206  ocs_log_err(ocs, "Chap list copy to user failed\n");
1207  ocs_unlock(&iscsi_api->api_list_lock);
1208  return -EFAULT;
1209  }
1210  offset += sizeof(ocs_chap_user_buffer_t);
1211  }
1212  ocs_unlock(&iscsi_api->api_list_lock);
1213 
1214  return 0;
1215 }
1216 
1217 static int32_t
1218 ocs_iscsi_unassisted_pdu_cb(struct ocs_hal_io_s *io,
1219  ocs_cxn_t *cxn,
1220  int32_t status,
1221  ocs_ini_cmpl_fields_t *ini_fields,
1222  void *ul_arg)
1223 {
1224  ocs_iscsi_pdu_cb_t cb;
1225  ocs_io_t *ocs_io;
1226  uint32_t exp_cmdsn = 0;
1227  uint32_t max_cmdsn = 0;
1228  uint8_t response = 0;
1229  int rc = 0;
1230 
1231  ocs_assert(cxn, -1);
1232  ocs_assert(ul_arg, -1);
1233 
1234  ocs_io = (ocs_io_t *)ul_arg;
1235 
1236  cb = ocs_io->unassisted_cb;
1237  ocs_io->unassisted_cb = NULL;
1238 
1239  if (ini_fields) {
1240  exp_cmdsn = ini_fields->exp_cmdsn;
1241  max_cmdsn = (ini_fields->exp_cmdsn + ini_fields->cmd_window - 1);
1242  response = ini_fields->response;
1243  }
1244 
1245  /* Copy the BHS back to io->bhs for open-iscsi */
1246  ocs_memcpy(ocs_io->bhs, io->bhs.virt, sizeof(iscsi_cmd_hdr_t));
1247 
1248  if (cb) {
1249  rc = cb(ocs_io, exp_cmdsn, max_cmdsn, response);
1250  }
1251  ocs_dma_free(cxn->ocs, &ocs_io->unassisted_payload);
1252 
1253  return rc;
1254 
1255 }
1256 
1257 int32_t
1258 ocs_iscsi_unassisted_pdu_send(ocs_t *ocs, ocs_io_t *io, ocs_cxn_t *cxn, void *bhs, void *data,
1259  uint32_t data_size, bool is_login, bool set_dm,
1260  ocs_iscsi_pdu_cb_t cb)
1261 {
1262  int rc;
1263  iscsi_bhs_t *iscsi_bhs;
1264 
1265  ocs_memcpy(io->bhs, bhs, sizeof(iscsi_cmd_hdr_t));
1266  io->node = cxn;
1267  io->ocs = cxn->ocs;
1268 
1269  // Save the caller's callback function
1270  io->unassisted_cb = cb;
1271  io->hal_io_size = data_size;
1272 
1273  iscsi_bhs = (iscsi_bhs_t *)bhs;
1274 
1275  /* If the PDU we're sending is a NOP OUT, and it's an initiator
1276  requesting a NOP IN response (rather than responding
1277  to a target's NOP IN request) then we have to send this is a
1278  INI_RD_CMD rather than as a DM_CMD. This is because with the
1279  DM_CMD, Skyhawk won't correctly return the NOP IN response back
1280  to us.
1281  */
1282  ocs_memset(&io->unassisted_payload, 0, sizeof(ocs_dma_t));
1283  if (data_size) {
1284  ocs_dma_alloc(ocs, &io->unassisted_payload,
1285  data_size, 16);
1286  ocs_memcpy(io->unassisted_payload.virt, data, data_size);
1287  }
1288 
1289  if ((iscsi_bhs->opcode == ISCSI_CMD_NOOP) && (iscsi_bhs->itt != ISCSI_RESERVED_TTT)) {
1290  iscsi_nopout_hdr_t *nop_hdr = bhs;
1291 
1292  io->io_type = OCS_HAL_IO_INITIATOR_READ;
1293  io->iparam.ini_io.lun = 0;
1294  io->iparam.ini_io.cmdsn = ocs_be32toh(nop_hdr->cmd_sn);
1295  io->iparam.ini_io.dif_info = NULL;
1296  } else {
1297  io->io_type = OCS_HAL_IO_UNASSISTED;
1298 
1299  io->iparam.unassisted.set_dm = set_dm;
1300  io->iparam.unassisted.incr_statsn = FALSE;
1301  io->iparam.unassisted.is_login = is_login;
1302  io->iparam.unassisted.payload1 =
1303  (data_size ? &io->unassisted_payload : NULL);
1304  }
1305 
1307 
1308 
1309  return rc;
1310 }
1311 
1312 int32_t
1313 ocs_iscsi_login_cb(ocs_hal_io_t *io, ocs_cxn_t *cxn,
1314  int32_t status,
1315  ocs_ini_cmpl_fields_t *ini_fields,
1316  void *ul_arg);
1317 
1318 /**
1319  * @brief Function to receieve the callback for a context update
1320  *
1321  * @param io pointer to the io object
1322  * @param cxn pointer to the connection object
1323  * @param status the status of the IO (1 = good)
1324  * @param ini_fields pointer to the initiator completion fields
1325  * @param ul_arg pointer to the login memory structure
1326  *
1327  * @return Returns 0 on success.
1328  */
1329 static int32_t
1331  int32_t status,
1332  ocs_ini_cmpl_fields_t *ini_fields,
1333  void *ul_arg)
1334 {
1335  ocs_iscsi_t *iscsi = cxn->iscsi;
1336 
1337  if (status != SLI_STATUS_SOL_CMD_CMPL_NORMAL &&
1338  status != SLI_STATUS_TCP_ACK_NOTIFY) {
1339  ocs_log_test(iscsi->os, "Invalid status %d\n", status);
1340  ocs_cxn_close(cxn, TRUE);
1341  }
1342 
1343  ocs_hal_io_free(iscsi->hal, io);
1344 
1345  return 0;
1346 }
1347 
1348 
1349 /**
1350  * @ingroup iscsi_api
1351  * @brief Sends the login parameters to the FW
1352  *
1353  * @param cxn pointer to the connection object
1354  *
1355  * @return Returns 0 on success.
1356  */
1357 int32_t
1359 {
1360  ocs_iscsi_t *iscsi = cxn->iscsi;
1361  ocs_session_t *session = cxn->session;
1362  ocs_hal_io_t *hal_io;
1363  ocs_hal_io_param_t iparam;
1364  int32_t rc;
1365 
1366  hal_io = ocs_hal_io_alloc(iscsi->hal);
1367  if (hal_io == NULL) {
1368  return OCS_PDU_RTN_NO_RESOURCES;
1369  }
1370 
1371  /*
1372  * Update the login parameters in FW
1373  */
1374  iparam.context_upd.lgn_options.session_options = session->login_options;
1375  iparam.context_upd.lgn_options.data_digest = cxn->data_digest;
1376  iparam.context_upd.lgn_options.hdr_digest = cxn->hdr_digest;
1377  iparam.context_upd.lgn_options.max_rcv_dsl = cxn->max_rcv_dsl;
1378  iparam.context_upd.lgn_options.max_send_dsl = cxn->max_xmit_dsl;
1379  iparam.context_upd.statsn = cxn->stat_sn;
1380  rc = ocs_hal_io_send(iscsi->hal,
1382  hal_io,
1383  0,
1384  &iparam,
1385  cxn,
1387  hal_io);
1388  return rc;
1389 }
1390 
1391 #if !defined(OCS_EXPORT)
1392 #define OCS_EXPORT(...)
1393 #endif
1394 
int32_t ocs_iscsi_unassisted_pdu_send(ocs_t *ocs, ocs_io_t *io, ocs_cxn_t *cxn, void *bhs, void *data, uint32_t data_size, bool is_login, bool set_dm, ocs_iscsi_pdu_cb_t cb)
uint32_t esi_listening
Definition: ocs_iscsi.h:283
char tgt_alias[OCS_ISCSI_MAX_ALIAS_SIZE]
structure for storing VLAN id and interface handle together
static void ocs_iscsi_api_isns_connect(ocs_t *ocs, void *ret, uint16_t nodes_count)
Logs into any remote targets discovered through iSNS that are not this device.
Defines the iSCSI command PDU header.
ocs_sport_t * ocs_iscsi_tgt_get_free_sport(ocs_t *ocs)
Get a next free sport object index.
Definition: ocs_iscsi_api.c:57
ocs_link_state_e
enum identifying the link state.
Definition: ocs_iscsi_api.h:66
int32_t ocs_iscsi_tgt_add(ocs_t *ocs, char *name, char *alias)
Adds a target.
void ocs_str_to_ip_struct(ocs_iscsi_t *iscsi, char *ip, ocs_ip_address_t *ip_struct)
Converts a string ip into an ip struct.
Definition: ocs_isns.c:256
int32_t ocs_iscsi_register_link_state_callback(ocs_t *ocs, ocs_link_state_cb_t cb)
Register to receive link state change notifications.
Definition: ocs_iscsi.c:3324
int32_t ocs_iscsi_isns_esi_listen_start(ocs_t *ocs, ocs_ip_address_t *ip, uint16_t tcp_port)
Starts an iSNS ESI TCP listen socket.
Definition: ocs_iscsi.c:1037
uint32_t ocs_iscsi_tgt_is_access_allowed(ocs_t *ocs, char *tgt_name, char *ini_name)
Checks if this initiator is allowed access to a target.
ocs_ip_address_t * ocs_iscsi_tgt_get_ip_address(ocs_t *ocs, char *tgt_name, uint32_t index)
Returns the IP address of the target name based on the index.
structure for storing CHAP usernames and passwords.
Definition: ocs_iscsi_api.h:91
ocs_hal_t * hal
Definition: ocs_iscsi.h:295
uint32_t ocs_iscsi_tgt_get_portal_group(ocs_t *ocs, char *tgt_name, ocs_ip_address_t *ip_address)
Returns the portal group of an IP address of the target name.
Defines the generic iSCSI basic header segment.
ocs_list_t chap_list
int32_t ocs_iscsi_mtu_set(ocs_t *ocs, uint8_t is_jumbo)
Sets the TCP MTU size of the iSCSI device.
Definition: ocs_iscsi.c:2173
ocs_lock_t api_list_lock
int8_t ocs_isns_register(ocs_iscsi_t *iscsi, uint8_t reg_tgts, uint8_t reg_ini, ocs_ip_address_t *isns_ip, char *eid)
Sends the DevAttrReg message to the iSNS server.
Definition: ocs_isns.c:1420
#define OCS_CHAP_MODE_TARGET
Definition: ocs_ioctl.h:275
char * ocs_get_iscsi_name(ocs_iscsi_t *iscsi, void *p, uint16_t index)
Gets the iscsi name of a given node.
Definition: ocs_isns.c:223
static int32_t ocs_iscsi_api_link_configure_thread(ocs_thread_t *mythread)
Configures the link on initial link up.
ocs_session_type_e
enum identifying the types of IP addresses.
Definition: ocs_iscsi_api.h:57
ocs_hal_target_login_options_t lgn_options
Definition: ocs_hal.h:563
ocs_hal_portal_t portal
Definition: ocs_iscsi.h:278
int32_t ocs_iscsi_listen_start(ocs_t *ocs, ocs_ip_address_t *ip, uint16_t tcp_port)
Starts a TCP listen socket.
Definition: ocs_iscsi.c:3227
void ocs_iscsi_ipsub_combine(ocs_ip_address_subnet_t *ipsub, ocs_ip_address_t *ip, ocs_ip_address_t *subnet)
Combines an iSCSI IP address and subnet into the combined structure.
Definition: ocs_iscsi.c:414
int32_t ocs_iscsi_chap_user_del(ocs_t *ocs, char *username, uint32_t type, uint32_t mode)
Delete CHAP user.
char isns_eid[40]
#define OCS_ISCSI_API_INIT_DELAY_MS
Definition: ocs_iscsi_api.c:46
char * ocs_iscsi_ini_get_name(ocs_t *ocs)
Return this initiator&#39;s name.
uint8_t ocs_iscsi_tgt_require_chap(ocs_t *ocs, char *tgt_name, ocs_session_type_e type)
Returns TRUE if CHAP is required for the session type.
const char * name
Definition: ocs_ddump.h:54
int32_t ocs_scsi_io_dispatch(ocs_io_t *io, void *cb)
Attempt to dispatch an IO.
Definition: ocs_scsi.c:475
ocs_mgmt_functions_t sport_mgmt_functions
Definition: ocs_sport.c:47
int32_t ocs_iscsi_send_context_udpate(ocs_cxn_t *cxn)
Sends the login parameters to the FW.
defines the parameters for an IO based on the IO type.
Definition: ocs_hal.h:501
uint32_t ocs_hal_portal_t
Definition: ocs_common.h:204
#define ISNS_ESI_PORT
Definition: ocs_isns.h:47
void ocs_iscsi_convert_to_hal_ip(ocs_ip_address_t *ip, ocs_hal_ip_address_t *hal_ip)
Convert an iSCSI IP address to the HAL IP address.
Definition: ocs_iscsi.c:359
uint32_t ip_added
Definition: ocs_iscsi.h:283
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
char * ocs_iscsi_tgt_get_names(ocs_t *ocs, uint32_t index)
Returns the target name based on the index.
ocs_ip_type_e ip_type
Definition: ocs_iscsi_api.h:75
bool cfg_thread_started
static void ocs_iscsi_api_link_configure(ocs_t *ocs)
Configures the link on initial link up.
#define OCS_CHAP_TYPE_INCOMING
Definition: ocs_ioctl.h:273
ocs_hal_io_t * ocs_hal_io_alloc(ocs_hal_t *hal)
Allocate a HAL IO object.
Definition: ocs_hal.c:5170
int32_t ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd,...)
Perform transport attach function.
Definition: ocs_xport.c:100
uint8_t * ocs_iscsi_mac_get(ocs_t *ocs)
Gets the MAC address of the iSCSI device.
Definition: ocs_iscsi.c:1323
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
char username[32]
Definition: ocs_iscsi_api.h:95
char * ocs_iscsi_get_chap_name(ocs_t *ocs, uint8_t sess_type, uint32_t mode, uint32_t type)
Returns the CHAP user name of corresponding type.
int32_t ocs_iscsi_chap_user_add(ocs_t *ocs, char *username, char *secret, uint32_t type, uint32_t mode)
Add CHAP user. If CHAP user of same type is already exists, return error.
static void ocs_iscsi_api_non_mgmt_config(ocs_t *ocs, ocs_hal_portal_t portal)
static void ocs_sport_lock_init(ocs_sport_t *sport)
Definition: ocs_common.h:116
static void ocs_iscsi_isns_configure(ocs_t *ocs, ocs_hal_portal_t portal, ocs_ip_address_t *isns_servers)
Register/query the iSNS server.
int32_t ocs_iscsi_listen_stop(ocs_t *ocs, ocs_ip_address_t *ip, uint16_t tcp_port)
Stops a TCP listen socket.
Definition: ocs_iscsi.c:3275
#define OCS_CTRLMASK_ISCSI_ISNS_ENABLE
ocs_ip_address_subnet_t ipsub
ocs_hal_portal_t ocs_iscsi_portal_get_default(ocs_t *ocs)
Retrieves the default portal.
Definition: ocs_iscsi.c:2816
uint16_t esi_port
Definition: ocs_iscsi.h:282
int32_t ocs_iscsi_ip_address_remove(ocs_t *ocs, ocs_hal_portal_t portal, ocs_ip_address_subnet_t *ipsub)
Remove the IP address to the specified interface.
Definition: ocs_iscsi.c:2510
void ocs_iscsi_api_link_state(ocs_t *ocs, ocs_link_state_e link_state)
Notifies the higher level iSCSI software of the link state.
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
ocs_hal_rtn_e ocs_hal_io_send(ocs_hal_t *hal, ocs_hal_io_type_e type, ocs_hal_io_t *io, uint32_t len, ocs_hal_io_param_t *iparam, ocs_cxn_t *cxn, io_cb_t cb, void *arg)
Send a read, write, or response IO.
Definition: ocs_hal.c:5370
char ini_name[OCS_MAX_ISCSI_NAME]
int32_t ocs_iscsi_is_ip_in_tbl(ocs_t *ocs, ocs_ip_address_subnet_t *ipsub)
Checks if an IP address/subnet is present in the table.
Definition: ocs_iscsi.c:2742
bool isns_registered
int32_t ocs_iscsi_ip_address_query(ocs_t *ocs, ocs_hal_portal_t portal, ocs_ip_type_e ip_type, uint32_t max_entries, uint32_t *num_ips, ocs_ip_address_subnet_t *ipsub)
Queries the IP addresses on the default interface.
Definition: ocs_iscsi.c:2567
uint8_t ip_address[16]
Definition: ocs_iscsi_api.h:76
#define ISCSI_RESERVED_TTT
uint32_t itt
#define ISCSI_CMD_NOOP
iSCSI object
Definition: ocs_iscsi.h:293
ocs_hal_portal_t iface_handle
int32_t ocs_iscsi_api_initialize(ocs_t *ocs)
Initialize the higher level iSCSI software.
HAL IO object.
Definition: ocs_hal.h:471
ocs_os_handle_t os
Definition: ocs_iscsi.h:294
#define OCS_EXPORT(...)
Definition: ocs_ddump.c:842
ocs_thread_t link_cfg_thread
Defines the iSCSI nop-out PDU header.
int32_t ocs_iscsi_chap_list_count(ocs_t *ocs)
Returns the count of chap_list.
ocs_ip_address_t gateway
int32_t ocs_iscsi_isns_esi_listen_stop(ocs_t *ocs, ocs_ip_address_t *ip, uint16_t tcp_port)
Stops an iSNS ESI TCP listen socket.
Definition: ocs_iscsi.c:1087
uint32_t listening
Definition: ocs_iscsi.h:283
uint16_t tcp_port
Definition: ocs_iscsi.h:281
struct ocs_hal_io_param_t::@17 context_upd
char * ocs_iscsi_get_chap_secret(ocs_t *ocs, char *name, uint32_t mode, uint32_t type, uint32_t *secret_len)
Returns the unenctypted CHAP secret for a specific user name. Note: Passwords should be at least 16 c...
void ocs_iscsi_rx_buffers_free(ocs_iscsi_t *iscsi, ocs_hal_rq_buffer_t *header, ocs_hal_rq_buffer_t *payload)
Add a receive buffer pair to the Receive Queue, if an error is received, then queue the buffer...
Definition: ocs_iscsi.c:4447
bool link_configured
int32_t ocs_iscsi_portal_delete(ocs_t *ocs, ocs_hal_portal_t portal)
Removes a previously-created portal.
Definition: ocs_iscsi.c:3183
void * ocs_isns_qry_tgts(ocs_iscsi_t *iscsi, ocs_ip_address_t *isns_ip, uint16_t *ret_nodes_count)
Sends the DevAttrReg message to the iSNS server.
Definition: ocs_isns.c:925
uint32_t opcode
int32_t ocs_iscsi_gateway_set(ocs_t *ocs, ocs_ip_address_t *gateway)
Sets the IP gateway address.
Definition: ocs_iscsi.c:2771
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
void ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a previously allocated HAL IO object.
Definition: ocs_hal.c:5231
int32_t ocs_iscsi_tgt_add_sport(ocs_t *ocs, ocs_sport_t *sport)
Add sport to iscsi target.
Definition: ocs_iscsi_api.c:85
structure wrapping an IP address and subnet together with their type.
Definition: ocs_iscsi_api.h:82
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
Definition: ocs_list.h:374
void format_ip_address(ocs_ip_type_e ip_type, uint8_t *address, char *buffer, int size)
Format an IP address into a string.
Definition: ocs_iscsi.c:460
char * ocs_get_ip(ocs_iscsi_t *iscsi, void *p, uint16_t index, uint16_t ip_index)
Gets the ip address of a given isns node.
Definition: ocs_isns.c:301
structure wrapping an IP address together with it&#39;s type.
Definition: ocs_hal.h:259
char * ocs_iscsi_ini_get_alias(ocs_t *ocs)
Returns the initiator alias.
int32_t ocs_cxn_connect(ocs_iscsi_t *iscsi, ocs_hal_ip_address_t *remote_ip, uint16_t tcp_port, char *tgt_name)
Log an initiator into the specified target address.
Definition: ocs_cxn.c:1498
defines a structure to contain the fields specific to an initiator IO completion. ...
Definition: ocs_hal.h:416
uint16_t ocs_get_port(ocs_iscsi_t *iscsi, void *p, uint16_t index, uint16_t ip_index)
Gets the port of a given isns node.
Definition: ocs_isns.c:325
ocs_ip_type_e
enum identifying the types of IP addresses.
Definition: ocs_iscsi_api.h:46
static uint8_t ocs_iscsi_api_not_local_target(ocs_t *ocs, char *remote_name)
Checks to see if the target name is this target.
uint32_t statsn
Definition: ocs_hal.h:564
int32_t ocs_iscsi_chap_list_get(ocs_t *ocs, char *userbuf, int32_t buflen)
Return CHAP list items.
bool enable_mgmt_flag
int32_t ocs_iscsi_ip_address_add(ocs_t *ocs, ocs_hal_portal_t portal, ocs_ip_address_subnet_t *ipsub)
Adds the IP address to the specified interface.
Definition: ocs_iscsi.c:2417
static void ocs_domain_lock(ocs_domain_t *domain)
Definition: ocs_common.h:186
static int32_t ocs_iscsi_unassisted_pdu_cb(struct ocs_hal_io_s *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
ocs_list_t portal_list
int32_t ocs_iscsi_inet_pton4(const char *src, ocs_ip_address_t *ip)
Converts an IPv4 address from a string to the IP structure.
Definition: ocs_iscsi.c:513
ocs_ip_address_t ip
Definition: ocs_iscsi.h:279
int32_t ocs_iscsi_isns_discover(ocs_t *ocs, ocs_hal_portal_t portal, uint32_t max_entries, uint32_t *num_ips, ocs_ip_address_t *ip)
Discovers the iSNS through the DHCP service.
Definition: ocs_iscsi.c:1138
#define OCS_MAX_SPORTS
Definition: ocs_drv_iscsi.h:57
Stores information needed to manage targets.
#define OCS_MAX_IP
Definition: ocs_iscsi.h:288
static int32_t ocs_iscsi_send_context_udpate_cb(ocs_hal_io_t *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
Function to receieve the callback for a context update.
void ocs_iscsi_unregister_link_state_callback(ocs_t *ocs, ocs_link_state_cb_t cb)
Unregister a link state change callback.
Definition: ocs_iscsi.c:3360
#define ocs_assert(cond,...)
Definition: ocs_debug.h:163
ocs_ip_address_t subnet
Definition: ocs_iscsi.h:280
#define OCS_MAX_ISCSI_NAME
Definition: ocs_common.h:240
char tgt_name[OCS_MAX_ISCSI_NAME]
#define OCS_ISCSI_TCP_PORT
ocs_iscsi_tgt_ip_t * ip_info
Definition: ocs_iscsi.h:332
int32_t ocs_iscsi_inet_pton6(const char *src, ocs_ip_address_t *ip)
Converts an IPv6 address from a string to the IP structure.
Definition: ocs_iscsi.c:574
ocs_ip_address_t * isns_servers
void * ocs_hal_get_ptr(ocs_hal_t *hal, ocs_hal_property_e prop)
Definition: ocs_hal.c:2753
uint32_t ocs_iscsi_get_max_cxns(ocs_t *ocs, char *tgt_name, char *ini_name)
Returns the maximum number of connections allowed per session.
int32_t(* ocs_iscsi_pdu_cb_t)(ocs_io_t *io, uint32_t exp_cmdsn, uint32_t max_cmdsn, uint8_t response)
ocs_list_t tgt_list
int32_t ocs_iscsi_login_cb(ocs_hal_io_t *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
structure wrapping an IP address together with it&#39;s type.
Definition: ocs_iscsi_api.h:74
void ocs_iscsi_tgt_del_sport(ocs_t *ocs, uint32_t sport_index)
Delete sport from iscsi target.
int32_t ocs_iscsi_add_ip_to_tbl(ocs_t *ocs, char *desc, ocs_ip_address_subnet_t *ipsub, ocs_hal_portal_t portal)
Adds an IP address to the table.
Definition: ocs_iscsi.c:2622
uint32_t exp_cmdsn
Definition: ocs_hal.h:418
char * ocs_iscsi_tgt_get_alias(ocs_t *ocs, uint32_t index)
Returns the target alias based on the index.
int32_t ocs_cxn_close(ocs_cxn_t *cxn, uint8_t sendRst)
Issues a request to the HAL to close the connection.
Definition: ocs_cxn.c:1648
int8_t ocs_isns_deregister(ocs_t *ocs, ocs_ip_address_t *isns_ip, char *eid)
Sends the DevDereg message to the iSNS server.
Definition: ocs_isns.c:1806
static const char chap[]
Definition: ocs_login.c:149
bool is_init_complete
Definition: ocs_iscsi.h:307
#define OCS_CHAP_TYPE_OUTGOING
Definition: ocs_ioctl.h:274
ocs_session_login_options_t session_options
Definition: ocs_hal.h:322
static void ocs_domain_unlock(ocs_domain_t *domain)
Definition: ocs_common.h:191
ocs_sem_t link_cfg_sem
uint32_t num_ips
Definition: ocs_iscsi.h:331
int32_t ocs_iscsi_api_shutdown(ocs_t *ocs)
Initialize the higher level iSCSI software.