Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_iscsi.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 interface functions.
36  */
37 
38 /**
39  * @defgroup iscsi_main iSCSI API
40  */
41 
42 /**
43  * @page iscsi_transport_api_overview Transport APIs and State Machine Functions
44  * - @ref scsi_api_base
45  * - @ref iscsi_main
46  * - @ref cxn_mgnt
47  * - @ref cxn_sm
48  *
49  * <div class="overview">
50  * <img src="elx_iscsi_trans.jpg" alt="iSCSI Transport" title="iSCSI Transport" align="right"/>
51  *
52  * <h2>iSCSI Transport</h2>
53  * Provides an abstracted SCSI interface to a back-end target and/or initiator.
54  * This allows access to the functionality of the HAL while using a
55  * transport agnostic API.
56  * The iSCSI transport module interfaces with the iHAL and takes all
57  * link/connection and unsolicited frame callbacks. It handles:
58  *
59  * <ul><li>TCP connections for both initiator and target functionality.</li>
60  * <li>Discovery and operational logins to remote target nodes.</li>
61  * <li>Accepts logins from remote initiators.</li></ul>
62  *
63  * The transport also performs the following:
64  *
65  * <ul><li>Exports target and initiator functions through the SCSI API.</li>
66  * <li>Performs iSCSI logins with remote nodes.</li>
67  * <li>Performs registration of the SLI Port with the HAL.</li>
68  * <li>Processes text PDU negotiation for SendTargets.</li>
69  * <li>Handles domain event callback notifications from the HAL.</li></ul>
70  *
71  * The iSCSI transport consists of the SCSI API, iSCSI API, link status handler components
72  * connection (node) state machine, and unsolicited PDU handler.
73  *
74  * <h3>SCSI API</h3>
75  * To enable the development of a SCSI initiator or target at a higher level than the
76  * SLI-4 and HAL, entry points have been defined and implemented in an API that uses
77  * SCSI semantics and concepts. For details on the SCSI API, see chapter 4, SCSI API, in the
78  * <i><a href="../../../../../doc/ocs_reference_driver_manual.pdf" target="_blank">OneCore Storage Reference Driver Manual</a></i>.
79  *
80  * <h3>Link Status Handler</h3>
81  * The link status handler provides the interface to the transport from the HAL's link
82  * events. The only functionality in this handler is to begin the TCP/IP configuration once
83  * the link is established. Nothing is done when the link is lost because the transport relies
84  * on the TCP time-outs before tearing down any connections.
85  *
86  * <h3>Connection (Node) State Machine</h3>
87  * The connection state machine implements the functions required to establish and maintain
88  * connections with remote nodes. Each node object has its own fully independent state
89  * machine instance. There are two node types that are created during the connection state
90  * machine operation:
91  *
92  * <ul><li>Remote SCSI initiator nodes</li>
93  * <li>Remote SCSI target nodes</li></ul>
94  *
95  * The general flow of a node in the connection state machine:
96  *
97  * <ol><li>The node is created and may transition to an initial state, depending on the type of
98  * node.</li>
99  * <li>Events are posted to the node state machine instance. For example, connection
100  * events received.</li>
101  * <li>The back-end components are notified of creation and deletion of nodes through
102  * the domain portion of the SCSI API.</li></ol>
103  *
104  * <h3>Connection Event Handler</h3>
105  * The connection handler provides the interface to the transport from the HAL's
106  * connection events. These include:
107  *
108  * <ul><li>New target connection notifications</li>
109  * <li>Connection Invalidation notifications</li>
110  * <li>Target data digest notifications</li></ul>
111  * On receipt of the connection event, it calls the appropriate handler function.
112  *
113  * <h3>Unsolicited PDU Handler</h3>
114  * Unsolicited iSCSI PDUs are received, and passed up to a target-server using the SCSI API.
115  * The unsolicited PDU handler provides the interface to the transport from the HAL's
116  * unsolicited iSCSI PDU events. These include:
117  *
118  * <ul><li>iSCSI login PDUs</li>
119  * <li>iSCSI text PDUs</li>
120  * <li>iSCSI command PDUs</li>
121  * <li>iSCSI task management PDUs</li>
122  * <li>iSCSI NOP PDUs</li>
123  * <li>iSCSI logout PDUs</li>
124  * <li>iSCSI reject PDUs</li></ul>
125  * On receipt of an Unsolicited PDU, the unsolicited PDU handler uses the TCP
126  * connection to find a corresponding node object instance. Based on the type of PDU
127  * received, the unsolicited PDU handler calls the appropriate handler function. In
128  * general, the unsolicited PDU handler rarely makes any function or protocol decisions,
129  * but merely dispatches PDUs to their respective handlers.
130  *
131  * <br><br>
132  * </div><!-- overview -->
133  */
134 
135 #include "ocs.h"
136 #include "ocs_iscsi.h"
137 #include "ocs_iscsi_spec.h"
138 #include "ocs_common.h"
139 #include "ocs_hal.h"
140 #include "ocs_iscsi_api.h"
141 #include "ocs_isns.h"
142 #include "ocs_login.h"
143 #include "ocs_session.h"
144 #include "ocs_cxn.h"
145 #include "sli4_iscsi.h"
146 
147 #define IDLE_TIMER_MS (30 * 1000) /* 30 seconds */
148 
149 static int32_t ocs_iscsi_hal_configure(ocs_iscsi_t *iscsi);
150 static int32_t ocs_iscsi_link_event_cb(void *arg, uint8_t isLinkUp);
151 static int32_t ocs_iscsi_cxn_event_cb(void *arg, ocs_hal_cxn_event_t *);
152 static int32_t ocs_iscsi_unsolicited_event_cb(void *arg,
153  ocs_cxn_t *cxn,
154  ocs_hal_rq_buffer_t *hdr,
155  uint32_t hdr_len,
156  ocs_hal_rq_buffer_t *data,
157  uint32_t data_len,
158  uint8_t code);
159 #if defined(OCS_INCLUDE_DEBUG)
160 static void ocs_iscsi_dump_active_ios(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn);
161 #endif
162 
163 
164 /**
165  * @brief Allocates an iSCSI API context that provides a synchronous API
166  * when using a asynchronous mailbox command.
167  *
168  * @param iscsi Pointer to the iSCSI object.
169  * @param index Index of the context to allocate.
170  *
171  * @return Returns pointer to the context if available, or NULL if it is in use.
172  */
173 static ocs_config_ctx_t*
175 {
176  int value;
177  ocs_config_ctx_t* rc = NULL;
178 
179  value = ocs_atomic_add_return(&iscsi->ctx[index].in_use, 1);
180  if (value == 0) {
181  rc = &iscsi->ctx[index];
182  } else {
183  (void)ocs_atomic_sub_return(&iscsi->ctx[index].in_use, 1);
184  }
185  return rc;
186 }
187 
188 /**
189  * @brief Waits on an iSCSI API context until the command completes or the
190  * timeout occurs.
191  *
192  * @param iscsi Pointer to the iSCSI object.
193  * @param index Index of the context to free.
194  * @param timeout_usec Timeout in microseconds.
195  *
196  * @return Returns 0 for success, or a negative value if the semaphore was not acquired.
197  */
198 static int32_t
199 ocs_iscsi_ctx_wait(ocs_iscsi_t *iscsi, ocs_config_ctx_e index, int timeout_usec)
200 {
201  int32_t rc = -1;
202  int delay;
203 
204  if (iscsi->shutting_down) {
205  /*
206  * During shutdown, we have to assume that we are no longer
207  * receiving interrupts, so call the HAL process function to
208  * see if the command completes.
209  */
210  while (timeout_usec > 0) {
211  ocs_hal_process(iscsi->hal,
212  0,
213  OCS_OS_MAX_ISR_TIME_MSEC);
214 
215  delay = MIN(timeout_usec, 1000);
216  rc = ocs_sem_p(&iscsi->ctx[index].sem, delay);
217 
218  /* Exit if the command is complete */
219  if (rc == 0) {
220  break;
221  }
222  timeout_usec -= delay;
223  }
224  } else {
225  rc = ocs_sem_p(&iscsi->ctx[index].sem, timeout_usec);
226  }
227  return rc;
228 }
229 
230 /**
231  * @brief Frees an iSCSI API context that provides a synchronous API
232  * when using a asynchronous mailbox command.
233  *
234  * @param iscsi Pointer to the iSCSI object.
235  * @param index Index of the context to free.
236  */
237 static void
239 {
240  (void)ocs_atomic_sub_return(&iscsi->ctx[index].in_use, 1);
241 }
242 
243 /**
244  * @brief Updates the status fields and post to the semaphore if it is still in use.
245  *
246  * @param ctx Pointer to the command context.
247  * @param status Status of the command.
248  * @param ext_status Extended status of the command.
249  */
250 static void
252  int32_t status,
253  uint32_t ext_status)
254 {
255  int in_use = ocs_atomic_read(&ctx->in_use);
256 
257  if (in_use) {
258  ctx->status = status;
259  ctx->ext_status = ext_status;
260  ocs_sem_v(&ctx->sem);
261  }
262 }
263 
264 /**
265  * @brief Completes any active iSCSI API context when the device is being
266  * shut down.
267  *
268  * @param iscsi Pointer to the iSCSI object.
269  *
270  * @return Returns the pointer to the context if available, or NULL if it is in use.
271  */
272 static void
274 {
275  ocs_config_ctx_t *ctx;
276  ocs_config_ctx_e index;
277  int in_use;
278 
279  for (index = 0; index < OCS_CNFG_CTX_MAX; index++) {
280  ctx = &iscsi->ctx[index];
281  in_use = ocs_atomic_read(&ctx->in_use);
282  if (in_use) {
283  ocs_iscsi_ctx_post(ctx, -1, -1);
284  }
285  }
286 }
287 
288 /**
289  * @brief Convert an iSCSI IP type to the HAL value.
290  *
291  * @param ip_type iSCSI IP type to convert.
292  *
293  * @return Returns the HAL IP type or OCS_HAL_IP_TYPE_V4 if an invalid value is passed.
294  */
297 {
299 
300  switch (ip_type) {
301  case OCS_IP_TYPE_V4:
302  rc = OCS_HAL_IP_TYPE_V4;
303  break;
304  case OCS_IP_TYPE_DHCP_V4:
306  break;
307  case OCS_IP_TYPE_V6:
308  rc = OCS_HAL_IP_TYPE_V6;
309  break;
310  case OCS_IP_TYPE_AUTO_V6:
312  break;
313  default:
314  break;
315  }
316  return rc;
317 }
318 
319 /**
320  * @brief Convert an HAL IP type to the iSCSI API value.
321  *
322  * @param ip_type HAL IP type to convert.
323  *
324  * @return Returns the iSCSI IP type or OCS_IP_TYPE_V4 if an invalid value is passed.
325  */
328 {
330 
331  switch (ip_type) {
332  case OCS_HAL_IP_TYPE_V4:
333  rc = OCS_IP_TYPE_V4;
334  break;
336  rc = OCS_IP_TYPE_DHCP_V4;
337  break;
338  case OCS_HAL_IP_TYPE_V6:
339  rc = OCS_IP_TYPE_V6;
340  break;
344  rc = OCS_IP_TYPE_AUTO_V6;
345  break;
346  default:
347  break;
348  }
349  return rc;
350 }
351 
352 /**
353  * @brief Convert an iSCSI IP address to the HAL IP address
354  *
355  * @param ip Pointer to the iSCSI IP address.
356  * @param hal_ip Pointer to the HAL IP address.
357  */
358 void
360 {
362  ocs_memcpy(hal_ip->ip_address, ip->ip_address, 16);
363 }
364 
365 /**
366  * @brief Convert an iSCSI IP address to the HAL IP address.
367  *
368  * @param ip Pointer to the iSCSI IP address.
369  * @param hal_ip Pointer to the HAL IP address.
370  */
371 void
373 {
375  ocs_memcpy(ip->ip_address, hal_ip->ip_address, 16);
376 }
377 
378 /**
379  * @brief Convert an iSCSI IP address to the HAL IP address.
380  *
381  * @param ip Pointer to the iSCSI IP address.
382  * @param hal_ip Pointer to the HAL IP address.
383  */
384 static void
386 {
388  ocs_memcpy(hal_ip->ip_address, ip->ip_address, 16);
389  ocs_memcpy(hal_ip->subnet, ip->subnet, 16);
390 }
391 
392 /**
393  * @brief Convert an iSCSI IP address to the HAL IP address.
394  *
395  * @param ip Pointer to the iSCSI IP address.
396  * @param hal_ip Pointer to the HAL IP address.
397  */
398 static void
400 {
402  ocs_memcpy(ip->ip_address, hal_ip->ip_address, 16);
403  ocs_memcpy(ip->subnet, hal_ip->subnet, 16);
404 }
405 
406 /**
407  * @brief Combines an iSCSI IP address and subnet into the combined structure.
408  *
409  * @param ipsub Pointer to the combined iSCSI IP/subnet address.
410  * @param ip Pointer to the IP address.
411  * @param subnet Pointer to the IP subnet address.
412  */
413 void
415  ocs_ip_address_t *ip,
416  ocs_ip_address_t *subnet)
417 {
418  ipsub->ip_type = ip->ip_type;
419  ocs_memcpy(ipsub->ip_address, ip->ip_address, ARRAY_SIZE(ipsub->ip_address));
420  ocs_memcpy(ipsub->subnet, subnet->ip_address, ARRAY_SIZE(ipsub->subnet));
421 }
422 
423 /**
424  * @brief Splits an iSCSI IP address and subnet from the combined structure.
425  *
426  * @param ipsub Pointer to the combined iSCSI IP/subnet address.
427  * @param ip Pointer to the IP address.
428  * @param subnet Pointer to the IP subnet address.
429  */
430 void
432  ocs_ip_address_t *ip,
433  ocs_ip_address_t *subnet)
434 {
435  ip->ip_type = ipsub->ip_type;
436  ocs_memcpy(ip->ip_address, ipsub->ip_address, ARRAY_SIZE(ip->ip_address));
437 
438  subnet->ip_type = ip->ip_type;
439  ocs_memcpy(subnet->ip_address, ipsub->subnet, ARRAY_SIZE(subnet->ip_address));
440 }
441 
442 /**
443  * @brief Format an IP address into a string
444  *
445  * @par Description
446  * Given a pointer to an IP address and a buffer, this function
447  * writes the IP address into the buffer in human readable form.
448  *
449  * @param ip_type Enumerated type indicating the type of IP
450  * address (IPV4, IPV6, etc).
451  * @param address Pointer to an array containing the IP address
452  * to be formatted. 4 bytes for IPV4, 16 bytes
453  * for IPV6.
454  * @param buffer Pointer to the buffer into which the result
455  * will be placed.
456  * @param size Size of the output buffer in bytes.
457  *
458  * @return None.
459  */
460 void format_ip_address(ocs_ip_type_e ip_type, uint8_t *address, char* buffer, int size)
461 {
462  uint32_t i;
463  int pos = 0;
464 
465  if (ip_type == OCS_IP_TYPE_V4 ||
466  ip_type == OCS_IP_TYPE_DHCP_V4) {
467  /* Print the IP address in IPV4 format */
468  ocs_snprintf(buffer, size, "%d.%d.%d.%d",
469  address[0],
470  address[1],
471  address[2],
472  address[3]);
473  } else {
474  /*
475  * Print the IP address in IPV6 format.
476  *
477  * If the two byte piece is zero, then only print a single zero
478  */
479  for (i = 0; i < 15; i += 2) {
480  if (address[i] != 0 || address[i + 1] != 0) {
481  ocs_snprintf(&buffer[pos],
482  size - pos,
483  "%02x%02x",
484  address[i], address[i + 1]);
485  pos += 4;
486  } else {
487  buffer[pos] = '0';
488  pos++;
489  }
490  /* Print the colon if we are not at the end */
491  if (i < 14) {
492  buffer[pos] = ':';
493  pos++;
494  }
495  }
496  /*
497  * The buffer may not be null terminated due to adding
498  * characters (0 and :) so just terminate it now.
499  */
500  buffer[pos] = '\0';
501  }
502 }
503 
504 /**
505  * @brief Converts an IPv4 address from a string to the IP structure.
506  *
507  * @param src Pointer to the ASCII IP address.
508  * @param ip Pointer to a IP address structure.
509  *
510  * @return Returns 0 for a valid IP address.
511  */
512 int32_t
514 {
515  bool have_digits = FALSE;
516  uint32_t src_index = 0;
517  uint32_t dest_index = 0;
518  uint32_t num_groups = 0;
519  char ch;
520 
521  ocs_memset(ip, 0, sizeof(ocs_ip_address_t));
522  ip->ip_type = OCS_IP_TYPE_V4;
523 
524  while ((ch = src[src_index]) != '\0')
525  {
526  if (ch >= '0' && ch <= '9')
527  {
528  uint32_t new_val = ((ip->ip_address[dest_index] * 10) +
529  (ch - '0'));
530 
531  if (have_digits && new_val == 0) {
532  return -1;
533  }
534  if (new_val > 255) {
535  return -1;
536  }
537  ip->ip_address[dest_index] = (uint8_t)new_val;
538  if (!have_digits)
539  {
540  if (++num_groups > 4) {
541  return -1;
542  }
543  have_digits = TRUE;
544  }
545  }
546  else if (ch == '.' && have_digits)
547  {
548  if (num_groups == 4) {
549  return -1;
550  }
551  dest_index++;
552  have_digits = FALSE;
553  } else {
554  return -1;
555  }
556  src_index++;
557  }
558  if (num_groups < 4) {
559  return -1;
560  }
561 
562  return 0;
563 }
564 
565 /**
566  * @brief Converts an IPv6 address from a string to the IP structure.
567  *
568  * @param src Pointer to the ASCII IP address.
569  * @param ip Pointer to an IP address structure.
570  *
571  * @return Returns 0 for a valid IP address.
572  */
573 int32_t
575 {
576  uint32_t src_index = 0;
577  uint32_t dest_index = 0;
578  bool have_digits = FALSE;
579  const char *curtok;
580  uint8_t *colonp;
581  char ch;
582  uint32_t val;
583  ocs_ip_address_t ipv4;
584 
585  ocs_memset(ip, 0, sizeof(ocs_ip_address_t));
586  ip->ip_type = OCS_IP_TYPE_V6;
587  colonp = NULL;
588 
589  /* Leading :: requires some special handling. */
590  if (src[src_index] == ':') {
591  src_index++;
592  if (src[src_index] != ':') {
593  return -1;
594  }
595  }
596 
597  curtok = &src[src_index];
598  have_digits = FALSE;
599  val = 0;
600  while ((ch = src[src_index]) != '\0')
601  {
602  int32_t digit = -1;
603 
604  src_index++;
605  if (ch >= '0' && ch <= '9'){
606  digit = (ch - '0');
607  } else if (ch >= 'A' && ch <= 'F') {
608  digit = 10 + (ch - 'A');
609  } else if (ch >= 'a' && ch <= 'f') {
610  digit = 10 + (ch - 'a');
611  }
612  if (digit != -1)
613  {
614  val <<= 4;
615  val |= digit;
616  if (val > 0xffff) {
617  return -1;
618  }
619  have_digits = TRUE;
620  continue;
621  }
622 
623  if (ch == ':') {
624  curtok = &src[src_index];
625  if (!have_digits) {
626  if (colonp) {
627  return -1;
628  }
629  colonp = &ip->ip_address[dest_index];
630  continue;
631  }
632  else if (src[src_index] == '\0') {
633  return -1;
634  }
635 
636  if (dest_index > 16) {
637  return -1;
638  }
639  ip->ip_address[dest_index++] = (val >> 8) & 0xff;
640  ip->ip_address[dest_index++] = val & 0xff;
641  have_digits = FALSE;
642  val = 0;
643  continue;
644  }
645 
646  if (ch == '.' && ((dest_index + 4) <= 16) &&
647  ocs_iscsi_inet_pton4(curtok, &ipv4) == 0)
648  {
649  ocs_memcpy(&ip->ip_address[dest_index], ipv4.ip_address, 4);
650  dest_index += 4;
651  have_digits = FALSE;
652  break; /* '\0' was seen by inet_pton4(). */
653  }
654  return -1;
655  }
656 
657  if (have_digits) {
658  if (dest_index + 2 > 16) {
659  return -1;
660  }
661  ip->ip_address[dest_index++] = (val >> 8) & 0xff;
662  ip->ip_address[dest_index++] = val & 0xff;
663  }
664 
665  if (colonp != NULL)
666  {
667  /*
668  * Since some memmove()'s erroneously fail to handle
669  * overlapping regions, we'll do the shift by hand.
670  */
671  uint32_t n = (uint32_t)(&ip->ip_address[dest_index] - colonp);
672  uint32_t i;
673 
674  if (dest_index == 16) {
675  return -1;
676  }
677 
678  for (i = 1; i <= n; i++)
679  {
680  ip->ip_address[16 - i] = colonp[n - i];
681  colonp[n - i] = '\0';
682  }
683  dest_index = 16;
684  }
685  if (dest_index != 16) {
686  return -1;
687  }
688 
689  return 0;
690 }
691 
692 /**
693  * @brief Format a MAC address into a string.
694  *
695  * @par Description
696  * Given a pointer to a MAC address and a buffer, this function
697  * writes the MAC address into the buffer in human readable
698  * form.
699  * @n @n
700  * @b Note: To avoid truncation, the output buffer must be at
701  * least 18 bytes long.
702  *
703  * @param address Pointer to an array of 6 bytes containing the
704  * MAC address.
705  * @param buffer Pointer to the buffer into which the result
706  * will be placed.
707  * @param size Size of the output buffer in bytes.
708  *
709  * @return None.
710  */
711 void format_mac_address(uint8_t *address, char* buffer, int size)
712 {
713  ocs_snprintf(buffer, size, "%02x:%02x:%02x:%02x:%02x:%02x",
714  address[0], address[1],
715  address[2], address[3],
716  address[4], address[5]);
717 }
718 
719 /**
720  * @brief Parse a string into a MAC address.
721  *
722  * @par Description
723  * This function parses a human readable MAC address into an
724  * array of 6 bytes.
725  * @n @n
726  * The input should be a string of six two-digit hex numbers,
727  * optionally separated by - or :. If the input string is not
728  * in one of these formats the results are undefined.
729  *
730  * @param src Pointer to the input string.
731  * @param dest Pointer to an array of at least 6 bytes in
732  * which the MAC address will be stored.
733  *
734  * @return Returns 0 on success; or -1 if the string does not
735  * represent a valid MAC address.
736  */
737 int32_t parse_mac_address(const char *src, uint8_t *dest)
738 {
739  char src_byte[3];
740  const char *src_p;
741  uint8_t *dest_p;
742  unsigned long value;
743  int byte;
744 
745  /*
746  * Validate the size of the input string. It should be exactly 12
747  * bytes if there are no separators between the bytes or 17 bytes if
748  * there are separators.
749  */
750 
751  if ((ocs_strlen(src) != 12) && (ocs_strlen(src) != 17)) {
752  return -1;
753  }
754 
755  src_p = src;
756  dest_p = dest;
757  for (byte=0; byte<6; byte++) {
758  src_byte[0] = *src_p++;
759  src_byte[1] = *src_p++;
760  src_byte[2] = '\0';
761  value = ocs_strtoul(src_byte, NULL, 16);
762  *dest_p++ = (uint8_t)value;
763  if ((*src_p == ':') || (*src_p == '-')) {
764  ++src_p;
765  }
766  }
767 
768  return 0;
769 
770 }
771 
772 
773 /**
774  * @brief Attempts to send an asynchronous message to request the initiator
775  * to logout.
776  *
777  * @param cxn Pointer to the connection object.
778  *
779  * @return Returns 0 on success.
780  */
781 static int32_t
783 {
784  ocs_t *ocs = cxn->ocs;
785  ocs_session_t *session = cxn->session;
786  int32_t rc = 0;
787 
788  if (cxn->cxn_state == CONN_STATE_FULL_FEATURE) {
789  if (session != NULL && session->is_discovery_session) {
790  /* just close the connection for discovery */
791  ocs_log_test(ocs, "Error on discovery connection %s, closing\n",
792  cxn->display_name);
793  ocs_cxn_close(cxn, FALSE);
794  } else {
795  ocs_log_debug(ocs, "Request logout for %s\n", cxn->display_name);
796 
797  rc = ocs_iscsi_send_async(cxn, NULL, 0, ASYNC_EVENT_CONN_CLOSE,
800  if (rc == 0) {
801  cxn->cxn_state = CONN_STATE_LOGOUT_REQUESTED;
802  }
803  }
804  } else {
805  ocs_log_debug(ocs, "state %d do not request logout for %s\n",
806  cxn->cxn_state, cxn->display_name);
807  }
808 
809  return rc;
810 }
811 
812 /**
813  * @brief This function is called to check for idle connections.
814  *
815  * @param arg Pointer to the iscsi object.
816  */
817 static void
819 {
820  ocs_iscsi_t *iscsi = arg;
821  ocs_t *ocs = iscsi->os;
822  ocs_cxn_t *cxn, *cxn_next;
823  uint32_t uerr_lo;
824  uint32_t uerr_hi;
825  uint32_t uerr_mask_lo;
826  uint32_t uerr_mask_hi;
827  ocs_sli_port_t *sport;
828 
829  /*
830  * Use this thread to monitor the error status registers. if a UE is
831  * detected, then dump all the IOs.
832  */
833  uerr_lo = sli_reg_read(&iscsi->hal->sli, SLI4_REG_UERR_STATUS_LO);
834  uerr_hi = sli_reg_read(&iscsi->hal->sli, SLI4_REG_UERR_STATUS_HI);
835  uerr_mask_lo = sli_reg_read(&iscsi->hal->sli, SLI4_REG_UERR_MASK_LO);
836  uerr_mask_hi = sli_reg_read(&iscsi->hal->sli, SLI4_REG_UERR_MASK_HI);
837  if (!iscsi->has_ue_occurred &&
838  (((uerr_lo & ~uerr_mask_lo) != 0) || ((uerr_hi & ~uerr_mask_hi) != 0))) {
839  iscsi->has_ue_occurred = TRUE;
840  ocs_log_crit(iscsi->os, "Error: uerr_hi: 0x%08x (0x%08x) uerr_lo: 0x%08x (0x%08x)\n",
841  uerr_hi, uerr_mask_hi, uerr_lo, uerr_mask_lo);
842 #if defined(OCS_INCLUDE_DEBUG)
843  ocs_domain_lock(ocs->hal.domain);
844  ocs_list_foreach(&ocs->hal.domain->sport_list, sport) {
845  ocs_sport_lock(sport);
846  ocs_list_foreach(&sport->node_list, cxn) {
847  ocs_iscsi_dump_active_ios(iscsi, cxn);
848  }
849  ocs_sport_unlock(sport);
850  }
851  ocs_domain_unlock(ocs->hal.domain);
852 #endif
853  }
854 
855 
856 
857  if (!iscsi->shutting_down) {
858  ocs_domain_lock(ocs->hal.domain);
859  ocs_list_foreach(&ocs->hal.domain->sport_list, sport) {
860  ocs_sport_lock(sport);
861  ocs_list_foreach_safe(&sport->node_list, cxn, cxn_next) {
862  if (cxn->no_idle_timer) {
863  continue;
864  }
865  cxn->idle_count++;
866  if (cxn->idle_count > 4 &&
867  cxn->cxn_state != CONN_STATE_CLEANUP &&
868  cxn->cxn_state != CONN_STATE_FREE) {
869  ocs_log_debug(iscsi->os, "killing idle connection%s\n", cxn->display_name);
870  ocs_cxn_close(cxn, TRUE);
871  } else if (cxn->cxn_state == CONN_STATE_FULL_FEATURE) {
872  /*
873  * For initiators, wait for 1 1/2 minutes before
874  * sending a nop (3 timer pops).
875  *
876  * For targets, wait 2 minutes, 4 pops.
877  */
878  if (cxn->is_ini_cxn) {
879  if (cxn->idle_count == 3) {
880  /* Send a nop-out (initiator) */
881  if (ocs_iscsi_send_nop_out(cxn,
882  ocs_be64toh(0),
883  0,
884  0xffffffff,
885  NULL,
886  0)) {
887  ocs_log_test(iscsi->os, "sending nop-out failed\n");
888  } else {
889  cxn->idle_count--;
890  }
891  }
892  /* Only target connections */
893  } else if (cxn->idle_count == 4) {
894  /* Send a nop-in (target) */
895  if (ocs_iscsi_send_nop_in(cxn,
896  ocs_be64toh(0),
897  0xffffffff,
898  (1 << 31) | cxn->wq_index,
899  NULL,
900  0)) {
901  ocs_log_test(iscsi->os, "sending nop-in failed\n");
902  } else {
903  cxn->idle_count--;
904  }
905  }
906  }
907  }
908  ocs_sport_unlock(sport);
909  }
910  ocs_domain_unlock(ocs->hal.domain);
911 
912  ocs_setup_timer(ocs, &iscsi->idle_timer,
914  iscsi,
915  IDLE_TIMER_MS, false);
916  }
917 }
918 
919 /**
920  * @brief This function is the callback a general API context command.
921  *
922  * @param ul_arg Pointer to the iscsi object.
923  * @param status Status of the command.
924  * @param ext_status Extended status of the command.
925  * @param params Points to the command parameters.
926  */
927 static void ocs_iscsi_ctx_general_cb(void *ul_arg,
928  int32_t status,
929  uint32_t ext_status,
930  void * params)
931 {
932  ocs_config_ctx_t *ctx = ul_arg;
933 
934  ocs_iscsi_ctx_post(ctx, status, ext_status);
935 }
936 
937 
938 /**
939  * @brief This function is the callback for the iSNS server IP addresses.
940  *
941  * @param ul_arg Pointer to the iscsi object.
942  * @param status Status of the command.
943  * @param ext_status Extended status of the command.
944  * @param params Pointer to ocs_hal_ip_address_subnet_t.
945  */
946 static void ocs_iscsi_isns_discover_cb(void *ul_arg,
947  int32_t status,
948  uint32_t ext_status,
949  void * params)
950 {
951  ocs_config_ctx_t *ctx = ul_arg;
952  int in_use = ocs_atomic_read(&ctx->in_use);
953  ocs_hal_ip_address_t *isns_servers = params;
954  ocs_ip_address_t ip;
955  uint32_t indx;
956 
957  ctx->num_ips = 0;
958 
959  if (in_use) {
960  if (status == 0 && isns_servers != NULL) {
961  for (indx = 0; indx < 8; indx++) {
962  if (isns_servers[indx].ip_type != 0) {
964  &isns_servers[indx]);
965  ctx->ip[ctx->num_ips] = ip;
966  ctx->num_ips++;
967  if (ctx->num_ips == ARRAY_SIZE(ctx->ip) - 1) {
968  break;
969  }
970  }
971  }
972  }
973  ocs_iscsi_ctx_post(ctx, status, ext_status);
974  }
975 }
976 
977 
978 /**
979  * @brief This function is the callback for the iSNS send.
980  *
981  * @param ul_arg Pointer to the iscsi object.
982  * @param status Status of the command.
983  * @param ext_status Extended status of the command.
984  * @param params Pointer to ocs_hal_ip_address_subnet_t.
985  */
986 static void ocs_iscsi_isns_send_cb(void *ul_arg,
987  int32_t status,
988  uint32_t ext_status,
989  void * params)
990 {
991  ocs_config_ctx_t *ctx = ul_arg;
992  int in_use = ocs_atomic_read(&ctx->in_use);
993  uint16_t *word = params;
994 
995  /*
996  * Build an iSNS PDU in big endian format
997  * Byte MSb LSb
998  * Offset 0 15 16 31
999  * +---------------------+----------------------+
1000  * 0 | iSNSP VERSION | FUNCTION ID | 4 Bytes
1001  * +---------------------+----------------------+
1002  * 4 | PDU LENGTH | FLAGS | 4 Bytes
1003  * +---------------------+----------------------+
1004  * 8 | TRANSACTION ID | SEQUENCE ID | 4 Bytes
1005  * +---------------------+----------------------+
1006  * 12 | |
1007  * | PDU PAYLOAD | N Bytes
1008  * | ... |
1009  * +--------------------------------------------+
1010  * 12+N | AUTHENTICATION BLOCK (Multicast/Broadcast) | L Bytes
1011  * +--------------------------------------------+
1012  */
1013  if (in_use) {
1014  ctx->isns_pkt_len = 0;
1015  ctx->num_ips = 0;
1016  if (status == 0 && word != NULL) {
1017  ctx->isns_pkt_len = 12 + ocs_be16toh(word[2]);
1018  if (ctx->isns_pkt_len > 0) {
1019  ocs_memcpy(ctx->isns_pkt,
1020  word,
1021  (ctx->isns_pkt_len > ctx->isns_buff_len ? ctx->isns_buff_len : ctx->isns_pkt_len));
1022  }
1023  }
1024  ocs_iscsi_ctx_post(ctx, status, ext_status);
1025  }
1026 }
1027 
1028 /**
1029  * @brief Starts an iSNS ESI TCP listen socket.
1030  *
1031  * @param ocs Pointer to the ocs structure that represents this device.
1032  * @param ip IP address to listen on.
1033  * @param tcp_port TCP port number to listen on.
1034  *
1035  * @return Returns 0 on success.
1036  */
1038  uint16_t tcp_port)
1039 {
1040  ocs_iscsi_t *iscsi = &ocs->iscsi;
1041  int32_t rc;
1042  ocs_config_ctx_t* ctx;
1043  ocs_hal_ip_address_t hal_ip;
1044 
1046  if (ctx == NULL) {
1047  ocs_log_err(iscsi->os, "context is busy\n");
1048  rc = -1;
1049  } else {
1050  ocs_iscsi_convert_to_hal_ip(ip, &hal_ip);
1052  &hal_ip,
1053  tcp_port,
1055  ctx);
1056  if (rc) {
1057  ocs_log_test(iscsi->os, "failed Starting ESI Listen\n");
1058  } else {
1060  3 * 1000000);
1061  if (rc == 0) {
1062  if (ctx->status != 0 ||
1063  ctx->ext_status != 0) {
1064  rc = -1;
1065  ocs_log_debug(iscsi->os, "starting ESI listen status 0x%x ext status 0x%x\n",
1066  ctx->status, ctx->ext_status);
1067  }
1068  }
1069  }
1071  }
1072 
1073  return rc;
1074 
1075 }
1076 
1077 
1078 /**
1079  * @brief Stops an iSNS ESI TCP listen socket.
1080  *
1081  * @param ocs Pointer to the ocs structure that represents this device.
1082  * @param ip IP address to listen on.
1083  * @param tcp_port TCP port number to listen on.
1084  *
1085  * @return Returns 0 on success.
1086  */
1088  uint16_t tcp_port)
1089 {
1090  ocs_iscsi_t *iscsi = &ocs->iscsi;
1091  int32_t rc;
1092  ocs_config_ctx_t* ctx;
1093  ocs_hal_ip_address_t hal_ip;
1094 
1096  if (ctx == NULL) {
1097  ocs_log_err(iscsi->os, "context is busy\n");
1098  rc = -1;
1099  } else {
1100  ocs_iscsi_convert_to_hal_ip(ip, &hal_ip);
1101  rc = ocs_hal_portal_esi_listen_stop(iscsi->hal,
1102  &hal_ip,
1103  tcp_port,
1105  ctx);
1106  if (rc) {
1107  ocs_log_test(iscsi->os, "failed Stopping ESI Listen\n");
1108  } else {
1110  3 * 1000000);
1111  if (rc == 0) {
1112  if (ctx->status != 0 ||
1113  ctx->ext_status != 0) {
1114  rc = -1;
1115  ocs_log_test(iscsi->os, "stopping ESI listen status 0x%x ext status 0x%x\n",
1116  ctx->status, ctx->ext_status);
1117  }
1118  }
1119  }
1121  }
1122 
1123  return rc;
1124 }
1125 
1126 
1127 /**
1128  * @brief Discovers the iSNS through the DHCP service.
1129  *
1130  * @param ocs Pointer to the ocs structure that represents this device.
1131  * @param portal Portal to use.
1132  * @param max_entries Maximum number of entries to be returned.
1133  * @param num_ips Actual number of entries returned.
1134  * @param ip IP address to listen on.
1135  *
1136  * @return Returns 0 on success.
1137  */
1139  uint32_t max_entries,
1140  uint32_t *num_ips,
1141  ocs_ip_address_t *ip)
1142 {
1143  ocs_iscsi_t *iscsi = &ocs->iscsi;
1144  int32_t rc;
1145  ocs_config_ctx_t* ctx;
1146 
1148  if (ctx == NULL) {
1149  ocs_log_err(iscsi->os, "context is busy\n");
1150  rc = -1;
1151  } else {
1152  rc = ocs_hal_portal_isns_discover(iscsi->hal,
1153  portal,
1155  ctx);
1156 
1157  if (rc) {
1158  ocs_log_test(iscsi->os, "iSNS Discover failed\n");
1159  } else {
1160  /* Bug 146254 - Use a 6 minute timeout */
1162  6 * 60 * 1000000);
1163  if (rc == 0) {
1164  if (ctx->status == 0 &&
1165  ctx->ext_status == 0) {
1166  *num_ips = MIN(ctx->num_ips, max_entries);
1167  ocs_memcpy(ip, ctx->ip,
1168  sizeof(ocs_ip_address_t) * *num_ips);
1169  } else {
1170  rc = -1;
1171  ocs_log_test(iscsi->os, "iSNS Discover status 0x%x ext status 0x%x\n",
1172  ctx->status, ctx->ext_status);
1173  }
1174  }
1175  }
1177  }
1178 
1179  return rc;
1180 }
1181 
1182 
1183 /**
1184  * @brief Sends an iSNS packet to a server to test the interface.
1185  *
1186  * @param ocs Pointer to the ocs structure that represents this device.
1187  * @param isns_server IP address of the iSNS server.
1188  * @param tcp_port TCP port number.
1189  * @param buffer Pointer to the virtual address of the iSNS buffer. This
1190  * buffer is used for both the request and response.
1191  * @param pkt_len Length of the packet and returns the length of the response.
1192  * @param buff_len Length of the buffer. Used to truncate the response if required.
1193  *
1194  * @return Returns 0 on success.
1195  */
1196 int32_t ocs_iscsi_isns_send(ocs_t *ocs,
1197  ocs_ip_address_t *isns_server,
1198  uint32_t tcp_port,
1199  void *buffer, uint32_t *pkt_len, uint32_t buff_len)
1200 {
1201  ocs_iscsi_t *iscsi = &ocs->iscsi;
1202  int32_t rc;
1203  ocs_config_ctx_t* ctx;
1204  ocs_hal_ip_address_t hal_ip;
1205 
1207  if (ctx == NULL) {
1208  ocs_log_err(iscsi->os, "context is busy\n");
1209  rc = -1;
1210  } else {
1211  ocs_iscsi_convert_to_hal_ip(isns_server, &hal_ip);
1212  ctx->isns_pkt = buffer;
1213  ctx->isns_pkt_len = *pkt_len;
1214  ctx->isns_buff_len = buff_len;
1216  &hal_ip,
1217  tcp_port,
1218  buffer,
1219  *pkt_len,
1221  ctx);
1222  if (rc) {
1223  ocs_log_test(iscsi->os, "iSNS Send failed\n");
1224  } else {
1226  12 * 1000000);
1227  if (rc == 0) {
1228  if (ctx->status == 0 &&
1229  ctx->ext_status == 0) {
1230  *pkt_len = ctx->isns_pkt_len;
1231  } else {
1232  rc = -1;
1233  ocs_log_test(iscsi->os, "iSNS Send status 0x%x ext status 0x%x\n",
1234  ctx->status, ctx->ext_status);
1235  }
1236  }
1237  }
1239  }
1240 
1241  return rc;
1242 }
1243 
1244 
1245 /**
1246  * @brief This function is the callback for querying IP addresses.
1247  *
1248  * @param ul_arg Pointer to the iSCSI object.
1249  * @param status Status of the command.
1250  * @param ext_status Extended status of the command.
1251  * @param params Pointer to ocs_hal_ip_address_subnet_t.
1252  */
1253 static void ocs_iscsi_query_ip_cb(void *ul_arg,
1254  int32_t status,
1255  uint32_t ext_status,
1256  void * params)
1257 {
1258  ocs_config_ctx_t *ctx = ul_arg;
1259  ocs_hal_get_ip_t *rtn = params;
1260  uint32_t i;
1261 
1262  ctx->num_ips = 0;
1263  if (status == 0) {
1264  ctx->num_ips = MIN(rtn->ip_count, ARRAY_SIZE(rtn->ipsub));
1265  for (i=0; i < ctx->num_ips; i++) {
1266  ocs_iscsi_convert_to_ipsub(&ctx->ipsub[i], &rtn->ipsub[i]);
1267  }
1268  }
1269  ocs_iscsi_ctx_post(ctx, status, ext_status);
1270 }
1271 
1272 
1273 /**
1274  * @brief Sets the MAC address of the iSCSI device.
1275  *
1276  * @param ocs Pointer to the ocs structure that represents this device.
1277  * @param mac_address Pointer to the MAC address value.
1278  *
1279  * @return Returns 0 on success.
1280  */
1281 int32_t ocs_iscsi_mac_set(ocs_t *ocs, uint8_t *mac_address)
1282 {
1283  ocs_iscsi_t *iscsi = &ocs->iscsi;
1284  ocs_config_ctx_t* ctx;
1285  int32_t rc = -1;
1286 
1288  if (ctx == NULL) {
1289  ocs_log_err(iscsi->os, "context is busy\n");
1290  rc = -1;
1291  } else {
1292  rc = ocs_hal_portal_set_mac(iscsi->hal,
1293  mac_address,
1295  ctx);
1296  if (rc) {
1297  ocs_log_test(iscsi->os, "failed setting MAC address\n");
1298  } else {
1300  1 * 1000000);
1301  if (rc == 0) {
1302  if (ctx->status != 0 ||
1303  ctx->ext_status != 0) {
1304  rc = -1;
1305  ocs_log_test(iscsi->os, "setting MAC address status 0x%x ext status 0x%x\n",
1306  ctx->status, ctx->ext_status);
1307  }
1308  }
1309  }
1311  }
1312  return rc;
1313 }
1314 
1315 /**
1316  * @brief Gets the MAC address of the iSCSI device.
1317  *
1318  * @param ocs Pointer to the ocs structure that represents this device.
1319  *
1320  * @return Returns a pointer to an array of 6 bytes containing
1321  * the MAC address of the interface.
1322  */
1323 uint8_t *ocs_iscsi_mac_get(ocs_t *ocs)
1324 {
1325  return ocs_hal_get_ptr(&ocs->hal, OCS_HAL_MAC_ADDR);
1326 }
1327 
1328 /**
1329  * @brief This function prints the module parameters to the log for
1330  * debugging purposes.
1331  *
1332  * @param iscsi Pointer to the iSCSI structure that represents this device
1333  */
1335 {
1336  ocs_t *ocs = iscsi->os;
1337 #if defined(OCS_INCLUDE_RAMD)
1338  char buffer[32];
1339 #endif
1340 
1341  ocs_log_debug(ocs, "Module parameters:\n");
1342  ocs_log_debug(ocs, " Initiator=%d\n", ocs->enable_ini);
1343  ocs_log_debug(ocs, " Target=%d\n", ocs->enable_tgt);
1344  ocs_log_debug(ocs, " ctrlmask=%d\n", ocs->ctrlmask);
1345  ocs_log_debug(ocs, " loglevel=%d\n", loglevel);
1346  ocs_log_debug(ocs, " enable_sgl_chaining=%d\n", ocs->enable_sgl_chaining);
1347  ocs_log_debug(ocs, " enable_immediate_data=%d\n", ocs->enable_immediate_data);
1348  ocs_log_debug(ocs, " enable_hdr_digest=%d\n", ocs->enable_hdr_digest);
1349  ocs_log_debug(ocs, " enable_data_digest=%d\n", ocs->enable_data_digest);
1350  ocs_log_debug(ocs, " enable_jumbo_frame=%d\n", ocs->enable_jumbo_frame);
1351  ocs_log_debug(ocs, " max_sge_size=%d\n", ocs->max_sge_size);
1352  ocs_log_debug(ocs, " post_sgl_config=%d\n", ocs->post_sgl_config);
1353 
1354 #if defined(OCS_INCLUDE_RAMD)
1355  ocs_get_property("ramdisc_blocksize", buffer, sizeof(buffer));
1356  ocs_log_debug(ocs, " ramdisc_blocksize=%s\n", buffer);
1357  ocs_get_property("ramdisc_size", buffer, sizeof(buffer));
1358  ocs_log_debug(ocs, " ramdisc_size=%s\n", buffer);
1359  ocs_get_property("p_type", buffer, sizeof(buffer));
1360  ocs_log_debug(ocs, " p_type=%s\n", buffer);
1361  ocs_get_property("num_luns", buffer, sizeof(buffer));
1362  ocs_log_debug(ocs, " num_luns=%s\n", buffer);
1363 #endif
1364 
1365  ocs_log_debug(ocs, " num_scsi_ios=%d\n", ocs->num_scsi_ios);
1366  ocs_log_debug(ocs, " local_ip=%s\n", ocs->local_ip);
1367  ocs_log_debug(ocs, " local_subnet=%s\n", ocs->local_subnet);
1368  ocs_log_debug(ocs, " gateway=%s\n", ocs->gateway);
1369  ocs_log_debug(ocs, " tcp_window_size=%d\n", ocs->tcp_window_size);
1370  ocs_log_debug(ocs, " tcp_window_scale=%d\n", ocs->tcp_window_scale);
1371  ocs_log_debug(ocs, " iqn_prefix=%s\n", ocs->iqn_prefix);
1372  ocs_log_debug(ocs, " iqn_suffix=%s\n", ocs->iqn_suffix);
1373 }
1374 
1375 
1376 #if defined(OCS_INCLUDE_RAMD)
1377 /**
1378  * @ingroup iscsi_main
1379  * @brief Configures the ramdisc specific parameters through the iSCSI API.
1380  *
1381  * @par Description
1382  * This function configures the target names and CHAP secrets via the iSCSI API.
1383  *
1384  * @param ocs Pointer to the ocs structure that represents this device.
1385  *
1386  * @return Returns 0 on success.
1387  */
1388 int32_t ocs_iscsi_ramd_configure(ocs_t *ocs)
1389 {
1390  char tgt_name[OCS_MAX_ISCSI_NAME];
1391  char tgt_alias[OCS_ISCSI_MAX_ALIAS_SIZE];
1392  uint8_t *mac;
1393  uint32_t i;
1394  uint32_t rc = 0;
1395 
1396  mac = ocs_hal_get_ptr(&ocs->hal, OCS_HAL_MAC_ADDR);
1397 
1398  for (i=0; i < ocs->num_tgts; i++) {
1399  if (0 == strncmp(ocs->iqn_suffix, OCS_IQN_SUFFIX_DEFAULT, 7))
1400  snprintf(tgt_name,
1402  "%s:%02x%02x%02x%02x%02x%02x:tgt%d.disk%d",
1403  ocs->iqn_prefix,
1404  mac[0], mac[1],mac[2],mac[3],mac[4],mac[5],
1405  ocs->instance_index,
1406  i);
1407  else
1408  snprintf(tgt_name,
1410  "%s:%s.disk%d",
1411  ocs->iqn_prefix, ocs->iqn_suffix, i);
1412  snprintf(tgt_alias,
1414  "%s:tgt%d.ramdisc%d",
1415  ocs->iqn_prefix+16,
1416  ocs->instance_index,
1417  i);
1418  if (ocs_iscsi_tgt_add(ocs, tgt_name, tgt_alias)) {
1419  ocs_log_test(ocs, "Error adding target name %s\n", tgt_name);
1420  rc = -1;
1421  }
1422  }
1423 
1424  if (ocs_is_target_enabled()) {
1425  if (ocs_iscsi_chap_user_add(ocs, "EmulexTgt", "ElxTgtPassword",
1428  ocs_log_err(ocs, "Error adding target CHAP credentials\n");
1429  rc = -1;
1430  }
1431 
1432  if (ocs_iscsi_chap_user_add(ocs, "EmulexTgtMutual",
1433  "ElxTgtPassMutual", OCS_CHAP_TYPE_OUTGOING,
1435  ocs_log_err(ocs, "Error adding target CHAP credentials\n");
1436  rc = -1;
1437  }
1438  }
1439 
1440  return rc;
1441 }
1442 #endif
1443 
1444 /**
1445  * @ingroup iscsi_main
1446  * @brief Returns the number of interrupts needed for this adapter.
1447  *
1448  * @par Description
1449  * This function queries the chip and determine the number of chutes. An
1450  * interrupt will be requested for each chute.
1451  *
1452  * @param os Pointer to the os structure that represents this device.
1453  * @param hal Pointer to the hal structure. Allocated in the OS specific
1454  * code due to ties to the hardware interrupt.
1455  *
1456  * @return Returns the number of interrupts required, or a negative value on failure.
1457  */
1458 int32_t
1459 ocs_iscsi_interrupts_required(ocs_os_handle_t os, ocs_hal_t *hal)
1460 {
1461  ocs_t *ocs = os;
1462  int32_t rc = 0;
1463  sli4_port_type_e port_type;
1464  uint32_t num_chutes = 0;
1465 
1467  port_type = SLI4_PORT_TYPE_ISCSI_BOTH;
1468  ocs_log_debug(os, "INI/TGT enabled\n");
1469  } else if (ocs_is_initiator_enabled()) {
1470  port_type = SLI4_PORT_TYPE_ISCSI_INI;
1471  ocs_log_debug(os, "INI enabled\n");
1472  } else {
1473  port_type = SLI4_PORT_TYPE_ISCSI_TGT;
1474  ocs_log_debug(os, "TGT enabled\n");
1475  }
1476 
1477  if ((rc = ocs_hal_setup(hal, os, port_type))) {
1478  ocs_log_err(os, "ocs_hal_setup failed\n");
1479  return -1;
1480  }
1481  ocs_hal_get(hal, OCS_HAL_NUM_CHUTES, &num_chutes);
1482 
1483  return num_chutes + 1;
1484 }
1485 
1486 
1487 /**
1488  * @ingroup iscsi_main
1489  * @brief Initialize the iSCSI device by setting up the chip.
1490  *
1491  * @par Description
1492  * This function initializes the chip and creates the necessary queues and
1493  * buffers.
1494  *
1495  * @param os Pointer to the os structure that represents this device.
1496  * @param iscsi Pointer to the iSCSI structure that represents this device.
1497  * @param hal Pointer to the hal structure. Allocated in the OS specific
1498  * code due to ties to the hardware interrupt.
1499  * @param device_instance Counter of the number of devices. Used to build
1500  * target names when non-global ramdisk is used.
1501  *
1502  * @return Returns 0 on success.
1503  */
1504 int32_t
1505 ocs_iscsi_initialize(ocs_os_handle_t os, ocs_iscsi_t *iscsi, ocs_hal_t *hal,
1506  uint32_t device_instance) {
1507  ocs_t *ocs = os;
1508  int32_t rc = 0;
1509  uint32_t i;
1510  uint8_t scsi_domains_added = FALSE;
1511  uint8_t scsi_sports_added = FALSE;
1512  uint8_t hal_sports_added = FALSE;
1513  uint8_t login_initialized = FALSE;
1514  uint8_t cxn_initialized = FALSE;
1515  uint8_t sess_initialized = FALSE;
1516  uint8_t isns_initialized = FALSE;
1517  uint8_t api_initialized = FALSE;
1518  uint32_t max_sgl;
1519  uint32_t ocs_chaining_enable;
1520 
1521  /* booleans used for cleanup if initialization fails */
1522  uint8_t ini_device_set = FALSE;
1523  uint8_t tgt_device_set = FALSE;
1524 
1525  iscsi->os = os;
1526  iscsi->hal = hal;
1527  iscsi->device_instance = device_instance;
1528 
1529  iscsi->ip_info = ocs_malloc(os, sizeof(*iscsi->ip_info) * OCS_MAX_IP,
1530  OCS_M_ZERO | OCS_M_NOWAIT);
1531  if (iscsi->ip_info == NULL) {
1532  ocs_log_err(os, "Failed to allocated ip_info lookup table\n");
1533  return -ENOMEM;
1534  }
1535 
1536  ocs_memset(iscsi->link_state_callbacks, 0, sizeof(iscsi->link_state_callbacks));
1537  ocs_lock_init(iscsi->os, &iscsi->link_state_cb_lock, "ocs_iscsi_cb_lock[%d]", ocs_instance(os));
1538 
1539  /*
1540  * Initialize the API context structures.
1541  */
1542  iscsi->ctx = ocs_malloc(os, sizeof(*iscsi->ctx) * OCS_CNFG_CTX_MAX,
1543  OCS_M_ZERO | OCS_M_NOWAIT);
1544  if (iscsi->ctx == NULL) {
1545  ocs_log_err(os, "Failed to allocated API contexts structures\n");
1546  rc = -1;
1547  goto exit_free_all;
1548  }
1549 
1550  for (i = 0; i < OCS_CNFG_CTX_MAX; i++) {
1551  iscsi->ctx[i].iscsi = iscsi;
1552  ocs_atomic_init(&iscsi->ctx[i].in_use, 0);
1553  ocs_sem_init(&iscsi->ctx[i].sem, 0, "api_ctx:%d", i);
1554  }
1555 
1556  if (ocs_is_target_enabled()) {
1557  if (ocs->num_tgts > OCS_MAX_SPORTS) {
1558  ocs_log_warn(iscsi->os, "set max_tgts to %d (exceeded Max)",
1559  OCS_MAX_SPORTS);
1560  ocs->num_tgts = iscsi->num_tgts = OCS_MAX_SPORTS;
1561  } else {
1562  iscsi->num_tgts = ocs->num_tgts;
1563  ocs_log_debug(iscsi->os, "set max_tgts to %d", ocs->num_tgts);
1564  if (ocs->num_tgts == 0) {
1565  ocs_log_test(iscsi->os, "ERROR: Number of targets is zero");
1566  rc = -1;
1567  goto exit_free_all;
1568  }
1569  }
1570  } else {
1571  iscsi->num_tgts = 1;
1572  }
1573 
1574  /* Print module parameters for debugging */
1576 
1577  /*
1578  * This code has been temporarily moved to ocs_iscsi_interrupts_required().
1579  * That function needs to know if the chip supports dual chute, so it has to
1580  * setup HAL. Because that function is called by ocs_pci_probe() before
1581  * calling ocs_device_attach, the HAL will already be setup by the time we get
1582  * here.
1583  *
1584  * {
1585  * sli4_port_type_e port_type;
1586  *
1587  * if (ocs_is_initiator_enabled() && ocs_is_target_enabled()) {
1588  * port_type = SLI4_PORT_TYPE_ISCSI_BOTH;
1589  * } else if (ocs_is_initiator_enabled()) {
1590  * port_type = SLI4_PORT_TYPE_ISCSI_INI;
1591  * } else {
1592  * port_type = SLI4_PORT_TYPE_ISCSI_TGT;
1593  * }
1594  * }
1595  *
1596  * if ((rc = ocs_hal_setup(hal, os, port_type))) {
1597  * ocs_log_err(iscsi->os, "ocs_hal_setup failed\n");
1598  * }
1599  */
1600 
1601  if (!rc) {
1602  if ((rc = ocs_iscsi_hal_configure(iscsi))) {
1603  ocs_log_err(iscsi->os, "ocs_iscsi_hal_configure failed\n");
1604  goto exit_free_all;
1605  }
1606  }
1607 
1608  if (!rc) {
1609  if ((rc = ocs_iscsi_login_initialize(iscsi))) {
1610  ocs_log_err(iscsi->os, "ocs_iscsi_login_initialize failed\n");
1611  goto exit_free_all;
1612  } else {
1613  login_initialized = TRUE;
1614  }
1615  }
1616 
1617  if (!rc) {
1618  /* Make sure to have equal/lesser number of SGEs as
1619  * we've configured in initiator mid-layer. */
1620  ocs_hal_get(hal, OCS_HAL_NUM_SGES_PER_ICD, &max_sgl);
1621  ocs_hal_get(hal, OCS_HAL_SGL_CHAINING_ENABLE, &ocs_chaining_enable);
1622  if (ocs_chaining_enable) {
1623  /* SGL chaining mode, use default SGL count. */
1624  max_sgl = OCS_DEFAULT_SGL_COUNT;
1625  }
1626  ocs->io_pool = ocs_io_pool_create(ocs, ocs->num_scsi_ios, MIN(64, max_sgl));
1627  if (ocs->io_pool == NULL) {
1628  rc = -1;
1629  goto exit_free_all;
1630  }
1631 
1632  ocs_list_init(&ocs->io_pending_list, ocs_io_t, io_pending_link);
1633  ocs_atomic_init(&ocs->io_active_count, 0);
1634  ocs_atomic_init(&ocs->io_pending_count, 0);
1635  ocs_atomic_init(&ocs->io_total_free, 0);
1636  ocs_atomic_init(&ocs->io_total_pending, 0);
1637  ocs_atomic_init(&ocs->io_pending_recursing, 0);
1638  }
1639 
1640 
1641  if (!rc) {
1642  if ((rc = ocs_iscsi_api_initialize(ocs))) {
1643  ocs_log_err(iscsi->os, "ocs_iscsi_api_initialize failed\n");
1644  } else {
1645  api_initialized = TRUE;
1646 #if defined(OCS_INCLUDE_RAMD)
1647  if (ocs_iscsi_ramd_configure(ocs)) {
1648  ocs_log_err(iscsi->os, "ocs_iscsi_ramd_configure failed\n");
1649  goto exit_free_all;
1650  }
1651 #endif
1652  }
1653  }
1654 
1655  if (!rc) {
1656  if ((rc = ocs_cxn_initialize(iscsi))) {
1657  ocs_log_err(iscsi->os, "ocs_cxn_initialize failed\n");
1658  goto exit_free_all;
1659  } else {
1660  cxn_initialized = TRUE;
1661  }
1662  }
1663 
1664  if (!rc) {
1665  if ((rc = ocs_session_initialize(iscsi))) {
1666  ocs_log_err(iscsi->os, "ocs_session_initialize failed\n");
1667  goto exit_free_all;
1668  } else {
1669  sess_initialized = TRUE;
1670  }
1671  }
1672 
1673  if (!rc) {
1674  if ((rc = ocs_isns_initialize(iscsi))) {
1675  ocs_log_err(iscsi->os, "ocs_isns_initialize failed\n");
1676  goto exit_free_all;
1677  } else {
1678  isns_initialized = TRUE;
1679  }
1680  }
1681 
1682  if (!rc) {
1683  ocs_domain_alloc(ocs);
1684  if (ocs->domain == NULL) {
1685  ocs_log_err(iscsi->os, "ocs_domain_alloc failed\n");
1686  rc = -ENOMEM;
1687  } else {
1688  ocs->domain->sport_instance_count = 0;
1689  ocs->domain->node_instance_count = 0;
1690  }
1691  }
1692 
1693  if (!rc) {
1694  if ((rc = ocs_hal_domain_add(hal, &ocs->sport[0], ocs->domain))) {
1695  ocs_log_err(iscsi->os, "adding domain to HAL failed\n");
1696  }
1697  }
1698 
1699  if (!rc) {
1700  uint8_t *mac;
1701 
1702  mac = ocs_hal_get_ptr(&ocs->hal, OCS_HAL_MAC_ADDR);
1703  for (i=0; i < iscsi->num_tgts; i++) {
1705  ocs->sport[i].domain = ocs->domain;
1706  ocs->sport[i].ocs = ocs;
1707  ocs->sport[i].index = i;
1708  ocs->sport[i].mgmt_functions = &sport_mgmt_functions;
1709 
1710  if (mac != NULL) {
1711  ocs_memcpy(ocs->sport[i].mac, mac, ARRAY_SIZE(ocs->sport[i].mac));
1712  ocs_snprintf(ocs->sport[i].mac_str,
1713  sizeof(ocs->sport[i].mac_str),
1714  "%02x%02x%02x%02x%02x%02x",
1715  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1716  }
1717 
1718  ocs_sport_lock_init(&ocs->sport[i]);
1719  ocs_list_init(&ocs->sport[i].node_list, ocs_node_t, link);
1720  ocs_domain_lock(ocs->hal.domain);
1721  ocs_list_add_tail(&ocs->domain->sport_list, &ocs->sport[i]);
1722  ocs->sport[i].created = TRUE;
1723  ocs_domain_unlock(ocs->hal.domain);
1724  }
1725  hal_sports_added = TRUE;
1726  }
1727 
1728  /* setup the transport object */
1729  if (!rc) {
1730  ocs->xport = ocs_xport_alloc(ocs);
1731  if (!ocs->xport) {
1732  ocs_log_err(iscsi->os, "Unable to allocate iSCSI transport\n");
1733  rc = -1;
1734  }
1735  }
1736 
1737  ocs->driver_version = DRV_VERSION;
1738  ocs->model = ocs_pci_model(ocs->pci_vendor, ocs->pci_device);
1739  ocs->fw_version = (const char*) ocs_hal_get_ptr(&ocs->hal, OCS_HAL_FW_REV);
1740 
1741  if (!rc) {
1742  if (ocs_is_initiator_enabled()) {
1743  rc = ocs_scsi_ini_new_device(ocs);
1744  if (rc == 0) {
1745  ini_device_set = TRUE;
1746  rc = ocs_scsi_ini_new_domain(ocs->domain);
1747  if (rc == 0) {
1748  scsi_domains_added = TRUE;
1749  ocs->sport[0].tgt_id = 0;
1750  rc = ocs_scsi_ini_new_sport(&ocs->sport[0]);
1751  if (rc == 0) {
1752  scsi_sports_added = TRUE;
1753  }
1754  }
1755  }
1756  }
1757  }
1758 
1759  if (!rc) {
1760  if (ocs_is_target_enabled()) {
1761  rc = ocs_scsi_tgt_new_device(ocs);
1762  if (rc == 0) {
1763  tgt_device_set = TRUE;
1764  rc = ocs_scsi_tgt_new_domain(ocs->domain);
1765  }
1766  for (i=0; i < iscsi->num_tgts; i++) {
1767  if (rc == 0) {
1768  scsi_domains_added = TRUE;
1769  ocs->sport[i].tgt_id = i;
1770  rc = ocs_scsi_tgt_new_sport(&ocs->sport[i]);
1771  if (rc == 0) {
1772  scsi_sports_added = TRUE;
1773  }
1774  }
1775  }
1776  }
1777  }
1778 
1779 
1780  if (!rc) {
1781  if ((rc = ocs_hal_init(hal))) {
1782  ocs_log_err(iscsi->os, "ocs_hal_init failed\n");
1783  } else {
1784  iscsi->is_hal_initialized = TRUE;
1785  }
1786  }
1787 
1788  /* Setup the idle connection timer on targets only */
1789  if (!rc) {
1790  ocs_setup_timer(ocs, &iscsi->idle_timer,
1792  iscsi,
1793  IDLE_TIMER_MS, false);
1794  }
1795 
1796 exit_free_all:
1797  if (rc) {
1798  uint32_t i;
1799 
1800  if (ocs->io_pool != NULL) {
1801  ocs_io_pool_free(ocs->io_pool);
1802  ocs->io_pool = NULL;
1803  }
1804 
1805  if (scsi_domains_added) {
1806  if (ocs_is_initiator_enabled()) {
1807  ocs_scsi_ini_del_domain(ocs->domain);
1808  }
1809  if (ocs_is_target_enabled()) {
1810  ocs_scsi_tgt_del_domain(ocs->domain);
1811  }
1812  }
1813 
1814  for (i=0; i < iscsi->num_tgts; i++) {
1815  if (scsi_sports_added) {
1816  if (ocs_is_initiator_enabled()) {
1817  ocs_scsi_ini_del_sport(&ocs->sport[i]);
1818  }
1819  if (ocs_is_target_enabled()) {
1820  ocs_scsi_tgt_del_sport(&ocs->sport[i]);
1821  }
1822  }
1823  if (hal_sports_added) {
1824  ocs_domain_lock(ocs->hal.domain);
1825  ocs_list_remove(&ocs->domain->sport_list, &ocs->sport[i]);
1826  ocs->sport[i].created = FALSE;
1827  ocs_domain_unlock(ocs->hal.domain);
1828  }
1829  }
1830 
1831  if (tgt_device_set) {
1833  }
1834 
1835  if (ini_device_set) {
1837  }
1838 
1839  if (login_initialized) {
1840  ocs_iscsi_login_teardown(iscsi);
1841  }
1842 
1843  if (ocs->domain != NULL) {
1844  ocs_domain_force_free(ocs->domain);
1845  ocs->domain = NULL;
1846  }
1847 
1848  if (cxn_initialized) {
1849  ocs_cxn_teardown(iscsi);
1850  }
1851 
1852  if (sess_initialized) {
1853  ocs_session_teardown(iscsi);
1854  }
1855 
1856  if (api_initialized) {
1858  }
1859 
1860  if (isns_initialized) {
1861  ocs_isns_teardown(iscsi);
1862  }
1863 
1864  if (iscsi->is_hal_initialized) {
1865  (void)ocs_hal_teardown(iscsi->hal);
1866  iscsi->is_hal_initialized = FALSE;
1867  }
1868 
1869  if (iscsi->ctx) {
1870  ocs_free(os, iscsi->ctx,
1871  sizeof(&iscsi->ctx) * OCS_CNFG_CTX_MAX);
1872  iscsi->ctx = NULL;
1873  }
1874 
1875  if (iscsi->ip_info) {
1876  ocs_free(os, iscsi->ip_info,
1877  sizeof(*iscsi->ip_info) * OCS_MAX_IP);
1878  iscsi->ip_info = NULL;
1879  }
1880 
1881  ocs_log_debug(iscsi->os, "Failed to initialize iSCSI\n");
1882  }
1883 
1884  iscsi->is_init_complete = 1;
1885  return rc;
1886 }
1887 
1888 /**
1889  * @ingroup iscsi_main
1890  * @brief Indicate that HAL is not initialized.
1891  *
1892  * @par Description
1893  * This function clears the is_hal_initialized flag for the given
1894  * iSCSI structure. This is to be used following a reset which causes
1895  * the HAL structures to no longer be valid. Clearing this bit prevents
1896  * the driver from trying to delete structures in the chip that are no
1897  * longer there.
1898  *
1899  * @param iscsi Pointer to the iSCSI structure that represents this device.
1900  *
1901  * @return None.
1902  */
1903 void
1905  iscsi->is_hal_initialized = FALSE;
1906 }
1907 
1908 /**
1909  * @ingroup iscsi_main
1910  * @brief Shut down the device
1911  *
1912  * @par Description
1913  * This function will shut down the PCI device and release all resources
1914  * allocated to it.
1915  *
1916  * @param iscsi Pointer to the iSCSI structure that represents this device.
1917  *
1918  * @return Returns 0 on success.
1919  */
1920 int32_t
1922  ocs_t *ocs = iscsi->os;
1923  int32_t rc = 0;
1924  uint32_t i;
1925 
1926  ocs_assert(iscsi, -1);
1927 
1928  ocs_log_debug(iscsi->os, "shutting down device\n");
1929  iscsi->shutting_down = TRUE;
1930 
1931  /* Cancel the idle timer */
1932  if (ocs_timer_pending(&iscsi->idle_timer)) {
1933  ocs_del_timer(&iscsi->idle_timer);
1934  }
1935 
1936  ocs_iscsi_ctx_teardown(iscsi);
1937 
1938  /* Teardown all of the connections */
1939  if (iscsi->hal->domain) {
1940  ocs_domain_force_free(iscsi->hal->domain);
1941  iscsi->hal->domain = NULL;
1942  }
1943 
1944  if (ocs_iscsi_api_shutdown(ocs)) {
1945  ocs_log_err(iscsi->os, "ocs_iscsi_api_shutdown() failed\n");
1946  }
1947 
1948  if (iscsi->is_hal_initialized) {
1949  rc = ocs_hal_teardown(iscsi->hal);
1950  iscsi->is_hal_initialized = FALSE;
1951 
1952  }
1953  /* delete sports, then domains */
1954  for (i=0; i < iscsi->num_tgts; i++) {
1955  if (ocs_is_initiator_enabled()) {
1956  ocs_scsi_ini_del_sport(&ocs->sport[i]);
1957  }
1958  if (ocs_is_target_enabled()) {
1959  ocs_scsi_tgt_del_sport(&ocs->sport[i]);
1960  }
1961  ocs_sport_lock_free(&ocs->sport[i]);
1962  }
1963  if (ocs_is_initiator_enabled()) {
1964  if (ocs->domain) {
1965  ocs_scsi_ini_del_domain(ocs->domain);
1966  }
1968  }
1969  if (ocs_is_target_enabled()) {
1970  if (ocs->domain) {
1971  ocs_scsi_tgt_del_domain(ocs->domain);
1972  }
1974  }
1975 
1976  if (ocs->domain) {
1977  rc |= ocs_hal_domain_free(iscsi->hal, ocs->domain);
1978  }
1979 
1980  ocs_iscsi_login_teardown(iscsi);
1981  ocs_session_teardown(iscsi);
1982  ocs_cxn_teardown(iscsi);
1983  ocs_isns_teardown(iscsi);
1984 
1985  ocs_lock_free(&iscsi->link_state_cb_lock);
1986 
1987  if (ocs->io_pool != NULL) {
1988  ocs_io_pool_free(ocs->io_pool);
1989  ocs->io_pool = NULL;
1990  }
1991 
1992  if (iscsi->ctx) {
1993  ocs_free(ocs, iscsi->ctx,
1994  sizeof(*iscsi->ctx) * OCS_CNFG_CTX_MAX);
1995  iscsi->ctx = NULL;
1996  }
1997 
1998  if (iscsi->ip_info) {
1999  ocs_free(ocs, iscsi->ip_info,
2000  sizeof(*iscsi->ip_info) * OCS_MAX_IP);
2001  iscsi->ip_info = NULL;
2002  }
2003 
2004  return rc;
2005 }
2006 
2007 /**
2008  * @brief Configure the HAL based on iSCSI compile parameters.
2009  *
2010  * @param iscsi Pointer to the iSCSI structure that represents this device.
2011  *
2012  * @return Returns 0 on success.
2013  */
2014 static int32_t
2016  ocs_t *ocs = iscsi->os;
2017  int32_t rc = 0;
2018  uint32_t sgl_chain_capable;
2019 
2020  if ((rc = ocs_hal_callback(iscsi->hal,
2023  iscsi))) {
2024  ocs_log_err(iscsi->os, "Failed setting link CB\n");
2025  }
2026 
2027  if (!rc) {
2028  if ((rc = ocs_hal_callback(iscsi->hal,
2031  iscsi))) {
2032  ocs_log_err(iscsi->os, "Failed setting conection CB\n");
2033  }
2034  }
2035 
2036  if (!rc) {
2037  if ((rc = ocs_hal_callback(iscsi->hal,
2040  iscsi))) {
2041  ocs_log_err(iscsi->os, "Failed setting unsolicited CB\n");
2042  }
2043  }
2044 
2045  if (!rc) {
2046  if ((rc = ocs_hal_get(iscsi->hal,
2048  &iscsi->pf_num))) {
2049  ocs_log_err(iscsi->os, "Failed getting PCI function\n");
2050  }
2051  }
2052 
2053  if (!rc) {
2054  if ((rc = ocs_hal_get(iscsi->hal,
2055  OCS_HAL_N_IO,
2056  &iscsi->num_ios))) {
2057  ocs_log_err(iscsi->os, "Failed getting number of IOs\n");
2058  }
2059  }
2060 
2061  if (!rc) {
2062  if ((rc = ocs_hal_get(iscsi->hal,
2064  &iscsi->num_cxns))) {
2065  ocs_log_err(iscsi->os, "Failed getting number of connections\n");
2066  }
2067  }
2068 
2069  /* Set the Dif mode */
2070  if (!rc) {
2071  uint32_t dif_capable;
2072  uint8_t dif_separate = 0;
2073  char prop_buf[32];
2074 
2075  if (0 == ocs_hal_get(&ocs->hal, OCS_HAL_DIF_CAPABLE, &dif_capable)) {
2076  if (dif_capable) {
2077  if (ocs_get_property("dif_separate", prop_buf, sizeof(prop_buf)) == 0) {
2078  dif_separate = ocs_strtoul(prop_buf, 0, 0);
2079  }
2080 
2081  if ((ocs_hal_set(iscsi->hal, OCS_HAL_DIF_MODE,
2082  (dif_separate == 0 ? OCS_HAL_DIF_MODE_INLINE : OCS_HAL_DIF_MODE_SEPARATE)))) {
2083  /* Not a fatal error */
2084  ocs_log_test(iscsi->os, "Failed setting the DIF MODE\n");
2085  }
2086  }
2087  }
2088  }
2089 
2090  ocs_log_debug(iscsi->os, "Driver configured for %d IOs\n", iscsi->num_ios);
2091  ocs_log_debug(iscsi->os, "Driver configured for %d connections\n", iscsi->num_cxns);
2092 
2093  if (!rc) {
2094  if (0 == ocs_hal_get(&ocs->hal, OCS_HAL_SGL_CHAINING_CAPABLE, &sgl_chain_capable)) {
2095  if (sgl_chain_capable) {
2096  if ((rc = ocs_hal_set(iscsi->hal,
2098  (ocs->enable_sgl_chaining ? 1 : 0)))) {
2099  ocs_log_err(iscsi->os, "Failed setting chaining SGL Enable\n");
2100  }
2101  }
2102  }
2103  }
2104 
2105  if (!rc && ocs->post_sgl_config != 0) {
2106  uint32_t num_sges = 0;
2107  uint32_t post_ver = 0;
2108 
2109  switch (ocs->post_sgl_config) {
2110  case 1:
2111  /* 32 SGEs per ICD Version 0 */
2112  num_sges = 32;
2113  post_ver = 0;
2114  break;
2115  case 2:
2116  /* 256 SGEs per ICD Version 0 */
2117  num_sges = 256;
2118  post_ver = 0;
2119  break;
2120  case 3:
2121  /* 32 SGEs per ICD Version 1 */
2122  num_sges = 32;
2123  post_ver = 1;
2124  break;
2125  case 4:
2126  /* 256 SGEs per ICD Version 1 */
2127  num_sges = 256;
2128  post_ver = 1;
2129  break;
2130  default:
2131  ocs_log_err(iscsi->os, "Invalid Post SGL configuration value of %d\n", ocs->post_sgl_config);
2132  rc = -1;
2133  }
2134 
2135  if (!rc) {
2136  if ((rc = ocs_hal_set(iscsi->hal,
2138  num_sges))) {
2139  ocs_log_err(iscsi->os, "Failed setting number of SGEs\n");
2140  }
2141  }
2142 
2143  if (!rc) {
2144  if ((rc = ocs_hal_set(iscsi->hal,
2146  post_ver))) {
2147  ocs_log_err(iscsi->os, "Failed setting Post_SGL version\n");
2148  }
2149  }
2150  }
2151 
2152  if (!rc) {
2153  if ((rc = ocs_hal_set_ptr(iscsi->hal,
2155  ocs->hal_war_version))) {
2156  ocs_log_err(iscsi->os, "Failed setting hal_war_version\n");
2157  }
2158  }
2159 
2160  return rc;
2161 }
2162 
2163 
2164 /**
2165  * @brief Sets the TCP MTU size of the iSCSI device.
2166  *
2167  * @param ocs Pointer to the ocs structure that represents this device
2168  * @param is_jumbo If TRUE, then the portal will be set for jumbo, otherwise
2169  * set for the standard 1500 bytes.
2170  *
2171  * @return Returns 0 on success.
2172  */
2173 int32_t ocs_iscsi_mtu_set(ocs_t *ocs, uint8_t is_jumbo)
2174 {
2175  ocs_iscsi_t *iscsi = &ocs->iscsi;
2176  int32_t rc;
2177  ocs_config_ctx_t* ctx;
2178 
2180  if (ctx == NULL) {
2181  ocs_log_err(iscsi->os, "context is busy\n");
2182  rc = -1;
2183  } else {
2184  rc = ocs_hal_portal_set_mtu(iscsi->hal,
2185  is_jumbo,
2187  ctx);
2188  if (rc) {
2189  ocs_log_test(iscsi->os, "failed setting TCP MTU size\n");
2190  } else {
2192  2 * 1000000);
2193  if (rc == 0) {
2194  if (ctx->status != 0 ||
2195  ctx->ext_status != 0) {
2196  rc = -1;
2197  ocs_log_test(iscsi->os, "setting MTU Size status 0x%x ext status 0x%x\n",
2198  ctx->status, ctx->ext_status);
2199  }
2200  }
2201  }
2203  }
2204 
2205  return rc;
2206 }
2207 
2208 /**
2209  * @brief iscsi cluster targets free
2210  */
2212 {
2213  ocs_iscsi_cluster_tgt_t *ctgt = NULL;
2215 
2216  ocs_list_foreach_safe(&iscsi->clusttgt.list, ctgt, next) {
2217  ocs_list_remove(&iscsi->clusttgt.list, ctgt);
2218  ocs_free(iscsi->os, ctgt, sizeof(*ctgt));
2219  ocs_atomic_sub_return(&iscsi->clusttgt.cnt, 1);
2220  }
2221  iscsi->clusttgt.ctgt_next = NULL;
2222  iscsi->clusttgt.send_en = false;
2223 }
2224 
2225 /**
2226  * @brief This function is the callback a add route table command.
2227  *
2228  * @param ul_arg Pointer to the iscsi object.
2229  * @param status Status of the command.
2230  * @param ext_status Extended status of the command.
2231  * @param params Points to the command parameters.
2232  */
2233 static void ocs_iscsi_ctx_route_table_read_cb(void *ul_arg,
2234  int32_t status,
2235  uint32_t ext_status,
2236  void *params)
2237 {
2238  ocs_config_ctx_t *ctx = ul_arg;
2239  ocs_iscsi_route_table_t *route_table = (ocs_iscsi_route_table_t *)params;
2240  uint32_t inx;
2241  int32_t ip_type;
2242 
2243  if (status == 0 && ext_status == 0) {
2244  memset(&ctx->route_table, 0, sizeof(ctx->route_table));
2245  ctx->route_table.entry_count = route_table->entry_count;
2246 
2247  for (inx = 0; inx < route_table->entry_count; inx++) {
2248  ip_type = ocs_iscsi_convert_to_ip_type(route_table->entry[inx].ip_addr.ip_type);
2249  ctx->route_table.entry[inx].ip_type = ip_type;
2250  format_ip_address(ip_type, route_table->entry[inx].ip_addr.ip_address,
2251  (char*)ctx->route_table.entry[inx].ip_addr,
2252  sizeof(ctx->route_table.entry[inx].ip_addr));
2253 
2254  ip_type = ocs_iscsi_convert_to_ip_type(route_table->entry[inx].subnet.ip_type);
2255  format_ip_address(ip_type, route_table->entry[inx].subnet.ip_address,
2256  (char*)ctx->route_table.entry[inx].subnet,
2257  sizeof(ctx->route_table.entry[inx].subnet));
2258 
2259  ip_type = ocs_iscsi_convert_to_ip_type(route_table->entry[inx].gateway.ip_type);
2260  format_ip_address(ip_type, route_table->entry[inx].gateway.ip_address,
2261  (char*)ctx->route_table.entry[inx].gateway,
2262  sizeof(ctx->route_table.entry[inx].gateway));
2263  }
2264  }
2265  ocs_iscsi_ctx_post(ctx, status, ext_status);
2266 }
2267 
2268 /**
2269  * @brief Deletes an entry from a routing table.
2270  *
2271  * @param ocs Pointer to the ocs structure that represents this device.
2272  * @param ipsub IP Address, subnet and gateway to delete.
2273  *
2274  * @return Returns 0 on success.
2275  */
2277  ocs_ip_address_subnet_t *ipsub,
2278  ocs_ip_address_t *gateway)
2279 {
2280  ocs_iscsi_t *iscsi = &ocs->iscsi;
2281  ocs_config_ctx_t *ctx;
2282  ocs_hal_ip_address_subnet_t hal_ipsub;
2283  ocs_hal_ip_address_t hal_gateway;
2284  int32_t timeout = 4 * 1000000;
2285  int32_t rc = -EFAULT;
2286 
2288  if (ctx == NULL) {
2289  ocs_log_err(iscsi->os, "context is busy\n");
2290  return rc;
2291  }
2292 
2293  ocs_iscsi_convert_to_hal_ipsub(ipsub, &hal_ipsub);
2294  ocs_iscsi_convert_to_hal_ip(gateway, &hal_gateway);
2295  rc = ocs_hal_portal_set_route_table(iscsi->hal,
2296  &hal_ipsub, &hal_gateway, FALSE,
2298  ctx);
2299  if (rc) {
2300  ocs_log_err(iscsi->os, "Submitting route table add entry failed\n");
2302  return rc;
2303  }
2304 
2305  rc = ocs_iscsi_ctx_wait(iscsi, OCS_CNFG_CTX_SET_ROUTE_TABLE, timeout);
2306  if (rc == 0) {
2307  if (ctx->status != 0 || ctx->ext_status != 0) {
2308  rc = -1;
2309  ocs_log_err(iscsi->os,
2310  "Route table entry add failed status 0x%x ext_stat 0x%x\n",
2311  ctx->status, ctx->ext_status);
2312  }
2313  }
2314 
2316  return rc;
2317 }
2318 
2319 
2320 /**
2321  * @brief Adds an entry to a routing table.
2322  *
2323  * @param ocs Pointer to the ocs structure that represents this device.
2324  * @param ipsub IP Address, subnet and gateway to add.
2325  *
2326  * @return Returns 0 on success.
2327  */
2329  ocs_ip_address_subnet_t *ipsub,
2330  ocs_ip_address_t *gateway)
2331 {
2332  ocs_iscsi_t *iscsi = &ocs->iscsi;
2333  ocs_config_ctx_t *ctx;
2334  ocs_hal_ip_address_subnet_t hal_ipsub;
2335  ocs_hal_ip_address_t hal_gateway;
2336  int32_t timeout = 4 * 1000000;
2337  int32_t rc = -EFAULT;
2338 
2340  if (ctx == NULL) {
2341  ocs_log_err(iscsi->os, "context is busy\n");
2342  return rc;
2343  }
2344 
2345  ocs_iscsi_convert_to_hal_ipsub(ipsub, &hal_ipsub);
2346  ocs_iscsi_convert_to_hal_ip(gateway, &hal_gateway);
2347  rc = ocs_hal_portal_set_route_table(iscsi->hal,
2348  &hal_ipsub, &hal_gateway, TRUE,
2350  ctx);
2351  if (rc) {
2352  ocs_log_err(iscsi->os, "Submitting route table add entry failed\n");
2354  return rc;
2355  }
2356 
2357  rc = ocs_iscsi_ctx_wait(iscsi, OCS_CNFG_CTX_SET_ROUTE_TABLE, timeout);
2358  if (rc == 0) {
2359  if (ctx->status != 0 || ctx->ext_status != 0) {
2360  rc = -1;
2361  ocs_log_err(iscsi->os,
2362  "Route table entry add failed status 0x%x ext_stat 0x%x\n",
2363  ctx->status, ctx->ext_status);
2364  }
2365  }
2366 
2368  return rc;
2369 }
2370 
2371 int32_t ocs_iscsi_route_table_read(ocs_t *ocs, ocs_route_table_t *route_table)
2372 {
2373  ocs_iscsi_t *iscsi = &ocs->iscsi;
2374  ocs_config_ctx_t *ctx;
2375  int32_t timeout = 4 * 1000000;
2376  int32_t rc = -EFAULT;
2377 
2379  if (ctx == NULL) {
2380  ocs_log_err(iscsi->os, "context is busy\n");
2381  return rc;
2382  }
2383 
2384  rc = ocs_hal_portal_get_route_table(iscsi->hal,
2386  if (rc) {
2387  ocs_log_err(iscsi->os, "Submitting get route table failed\n");
2389  return rc;
2390  }
2391 
2392  rc = ocs_iscsi_ctx_wait(iscsi, OCS_CNFG_CTX_GET_ROUTE_TABLE, timeout);
2393  if (rc == 0) {
2394  if (ctx->status != 0 || ctx->ext_status != 0) {
2395  rc = -1;
2396  ocs_log_err(iscsi->os,
2397  "Get route table failed status 0x%0x ext_stat 0x%x\n",
2398  ctx->status, ctx->ext_status);
2399  } else {
2400  ocs_memcpy(route_table, &ctx->route_table, sizeof(*route_table));
2401  }
2402  }
2403 
2405  return rc;
2406 }
2407 
2408 /**
2409  * @brief Adds the IP address to the specified interface.
2410  *
2411  * @param ocs Pointer to the ocs structure that represents this device.
2412  * @param portal Portal to use.
2413  * @param ipsub IP Address and subnet to add.
2414  *
2415  * @return Returns 0 on success.
2416  */
2417 int32_t ocs_iscsi_ip_address_add(ocs_t *ocs,
2418  ocs_hal_portal_t portal,
2419  ocs_ip_address_subnet_t *ipsub)
2420 {
2421  ocs_iscsi_t *iscsi = &ocs->iscsi;
2422  int32_t rc;
2423  ocs_config_ctx_t* ctx;
2424  ocs_hal_ip_address_subnet_t hal_ipsub;
2425  int timeout = 4 * 1000000;
2426  ocs_ip_address_subnet_t *ipsub_tbl;
2427  uint32_t num_ips;
2428  uint32_t i;
2429 
2430  ipsub_tbl = ocs_malloc(ocs, sizeof(ocs_ip_address_subnet_t) * OCS_MAX_IP,
2431  OCS_M_ZERO | OCS_M_NOWAIT);
2432  if (ipsub_tbl == NULL) {
2433  ocs_log_err(iscsi->os, "failed allocating IP table memory\n");
2434  rc = -1;
2435  } else {
2437  if (ctx == NULL) {
2438  ocs_log_err(iscsi->os, "context is busy\n");
2439  rc = -1;
2440  } else {
2441  /* Bug 146254 - Use a 6 minute timeout */
2442  if (ipsub->ip_type == OCS_IP_TYPE_DHCP_V4 ||
2443  ipsub->ip_type == OCS_IP_TYPE_AUTO_V6) {
2444  timeout = 6 * 60 * 1000000;
2445  }
2446 
2447  ocs_iscsi_convert_to_hal_ipsub(ipsub, &hal_ipsub);
2448  rc = ocs_hal_portal_ip_add(iscsi->hal,
2449  portal,
2450  &hal_ipsub,
2452  ctx);
2453  if (rc) {
2454  ocs_log_test(iscsi->os, "failed adding IP\n");
2455  } else {
2456  rc = ocs_iscsi_ctx_wait(iscsi, OCS_CNFG_CTX_IP_ADD, timeout);
2457  /* For Auto addresses get the new address */
2458  if (rc == 0) {
2459  if (ctx->status == 0 &&
2460  ctx->ext_status == 0) {
2461  if (ipsub->ip_type == OCS_IP_TYPE_DHCP_V4 ||
2462  ipsub->ip_type == OCS_IP_TYPE_AUTO_V6) {
2463  rc = ocs_iscsi_ip_address_query(ocs,
2464  portal,
2465  ipsub->ip_type,
2466  OCS_MAX_IP,
2467  &num_ips,
2468  ipsub_tbl);
2469  if (rc == 0) {
2470  for(i = 0; i < num_ips; i++) {
2471  if (ipsub_tbl[i].ip_type == ipsub->ip_type) {
2472  /* Copy back to caller */
2473  ocs_memcpy(ipsub,
2474  &ipsub_tbl[i],
2475  sizeof(*ipsub));
2476  break;
2477  }
2478  }
2479  }
2480  }
2481  /* Add the IP (recevied with DHCP or static IP) to OCS device table*/
2482  ocs_iscsi_add_ip_to_tbl(ocs, "Added", ipsub, portal);
2483  } else {
2484  rc = -1;
2485  ocs_log_test(iscsi->os, "adding IP status 0x%x ext status 0x%x\n",
2486  ctx->status, ctx->ext_status);
2487  }
2488  }
2489  }
2491  }
2492  }
2493 
2494  if (ipsub_tbl != NULL) {
2495  ocs_free(ocs, ipsub_tbl, sizeof(ocs_ip_address_subnet_t) * OCS_MAX_IP);
2496  }
2497 
2498  return rc;
2499 }
2500 
2501 /**
2502  * @brief Remove the IP address to the specified interface.
2503  *
2504  * @param ocs Pointer to the ocs structure that represents this device.
2505  * @param portal Portal to use.
2506  * @param ipsub IP Address and subnet to remove.
2507  *
2508  * @return Returns 0 on success.
2509  */
2510 int32_t ocs_iscsi_ip_address_remove(ocs_t *ocs,
2511  ocs_hal_portal_t portal,
2512  ocs_ip_address_subnet_t *ipsub)
2513 {
2514  ocs_iscsi_t *iscsi = &ocs->iscsi;
2515  int32_t rc;
2516  ocs_config_ctx_t* ctx;
2517  ocs_hal_ip_address_subnet_t hal_ipsub;
2518 
2520  if (ctx == NULL) {
2521  ocs_log_err(iscsi->os, "context is busy\n");
2522  rc = -1;
2523  } else {
2524  ocs_iscsi_convert_to_hal_ipsub(ipsub, &hal_ipsub);
2525  rc = ocs_hal_portal_ip_remove(iscsi->hal,
2526  portal,
2527  &hal_ipsub,
2529  ctx);
2530  if (rc) {
2531  ocs_log_test(iscsi->os, "Error %d removing IP\n", rc);
2532  } else {
2534  3 * 1000000);
2535  if (rc == 0) {
2536  if ((ctx->status == 0) && (ctx->ext_status == 0)) {
2537  ocs_iscsi_remove_ip_from_tbl(ocs, ipsub, portal);
2538  } else {
2539  rc = -1;
2540  ocs_log_test(iscsi->os, "Removing IP status 0x%x ext status 0x%x\n",
2541  ctx->status, ctx->ext_status);
2542  }
2543  } else {
2544  ocs_log_test(iscsi->os, "Timeout Removing IP\n");
2545  }
2546  }
2548  }
2549 
2550  return rc;
2551 }
2552 
2553 
2554 /**
2555  * @brief Queries the IP addresses on the default interface.
2556  *
2557  * @param ocs Pointer to the ocs structure that represents this device.
2558  * @param portal Portal to use.
2559  * @param ip_type Enumerated type indicating the type of IP
2560  * address (IPV4, IPV6, etc).
2561  * @param max_entries Maximum number of entries to be returned.
2562  * @param num_ips Actual number of entries returned.
2563  * @param ipsub Used to return queried IP addresses.
2564  *
2565  * @return Returns 0 on success.
2566  */
2567 int32_t ocs_iscsi_ip_address_query(ocs_t *ocs,
2568  ocs_hal_portal_t portal,
2569  ocs_ip_type_e ip_type,
2570  uint32_t max_entries,
2571  uint32_t *num_ips,
2572  ocs_ip_address_subnet_t *ipsub)
2573 {
2574  ocs_iscsi_t *iscsi = &ocs->iscsi;
2575  int32_t rc = -1;
2576  ocs_config_ctx_t* ctx;
2577 
2578  *num_ips = 0;
2580  if (ctx == NULL) {
2581  ocs_log_err(iscsi->os, "context is busy\n");
2582  rc = -1;
2583  } else {
2584  rc = ocs_hal_portal_ip_get(iscsi->hal,
2585  portal,
2588  ctx);
2589  if (rc) {
2590  ocs_log_test(iscsi->os, "failed querying IPs\n");
2591  } else {
2593  1 * 1000000);
2594  if (rc == 0) {
2595  if (ctx->status == 0 &&
2596  ctx->ext_status == 0) {
2597  *num_ips = MIN(ctx->num_ips, max_entries);
2598  ocs_memcpy(ipsub, ctx->ipsub,
2599  sizeof(ocs_ip_address_subnet_t) * *num_ips);
2600  } else {
2601  rc = -1;
2602  ocs_log_test(iscsi->os, "querying IPs status 0x%x ext status 0x%x\n",
2603  ctx->status, ctx->ext_status);
2604  }
2605  }
2606  }
2608  }
2609 
2610  return rc;
2611 }
2612 
2613 /**
2614  * @brief Adds an IP address to the table.
2615  *
2616  * @param ocs Pointer to the ocs structure.
2617  * @param desc A character description of the IP address being added.
2618  * @param ipsub Pointer to the IP/subnet structure.
2619  * @param portal Portal that has the IP address.
2620  */
2621 int32_t
2623  char *desc,
2624  ocs_ip_address_subnet_t *ipsub,
2625  ocs_hal_portal_t portal)
2626 {
2627  ocs_iscsi_t *iscsi = &ocs->iscsi;
2628  ocs_ip_address_t ip;
2629  ocs_ip_address_t subnet;
2630  char ip_str[40];
2631  char mask_str[40];
2632  char *ip_type_str;
2633  int32_t rc = 0;
2634 
2635  switch (ipsub->ip_type) {
2636  case OCS_IP_TYPE_V4:
2637  ip_type_str = "v4";
2638  break;
2639  case OCS_IP_TYPE_DHCP_V4:
2640  ip_type_str = "DHCP";
2641  break;
2642  case OCS_IP_TYPE_V6:
2643  ip_type_str = "v6";
2644  break;
2645  case OCS_IP_TYPE_AUTO_V6:
2646  ip_type_str = "Auto v6";
2647  break;
2648  default:
2649  ip_type_str = "Invalid";
2650  break;
2651  }
2652 
2653 
2654  ocs_iscsi_ipsub_split(ipsub,
2655  &ip,
2656  &subnet);
2657 
2659  ip.ip_address,
2660  ip_str, sizeof(ip_str));
2661  format_ip_address(subnet.ip_type,
2662  subnet.ip_address,
2663  mask_str, sizeof(mask_str));
2664  ocs_log_debug(ocs, "Adding %s IP address %s mask %s type %s\n",
2665  desc,
2666  ip_str,
2667  mask_str,
2668  ip_type_str);
2669 
2670  if (iscsi->num_ips < OCS_MAX_IP) {
2671  ocs_iscsi_tgt_ip_t *api_ip = &iscsi->ip_info[iscsi->num_ips];
2672  api_ip->portal = portal;
2673  api_ip->ip = ip;
2674  api_ip->subnet = subnet;
2675  api_ip->tcp_port = 0;
2676  api_ip->ip_added = 1;
2677  api_ip->listening = 0;
2678  iscsi->num_ips++;
2679  } else {
2680  ocs_log_warn(ocs, "IP Table overflow\n");
2681  rc = -1;
2682  }
2683  return rc;
2684 }
2685 
2686 /**
2687  * @brief Remove an IP address from the table.
2688  *
2689  * @param ocs Pointer to the ocs structure.
2690  * @param ipsub Pointer to the IP/subnet structure.
2691  * @param portal Portal that has the IP address.
2692  *
2693  * @return Returns 0 if the address was removed, or -1 if the address was not found.
2694  */
2695 int32_t
2697  ocs_ip_address_subnet_t *ipsub,
2698  ocs_hal_portal_t portal)
2699 {
2700  ocs_iscsi_t *iscsi = &ocs->iscsi;
2701  ocs_ip_address_t ip;
2702  ocs_ip_address_t subnet;
2703  uint32_t i;
2704  int rc = -1;
2705  int found_at = -1;
2706 
2707  ocs_iscsi_ipsub_split(ipsub, &ip, &subnet);
2708  for (i = 0; i < iscsi->num_ips; i++) {
2709  ocs_iscsi_tgt_ip_t *api_ip = &iscsi->ip_info[i];
2710  if (memcmp(&api_ip->ip, &ip, sizeof(ip)) == 0 &&
2711  memcmp(&api_ip->subnet, &subnet, sizeof(subnet)) == 0) {
2712  found_at = i;
2713  break;
2714  }
2715  }
2716 
2717  if (found_at != -1) {
2718  // Remove the item
2719  for (i=found_at; i<iscsi->num_ips; i++) {
2720  ocs_iscsi_tgt_ip_t *src = &iscsi->ip_info[i+1];
2721  ocs_iscsi_tgt_ip_t *dst = &iscsi->ip_info[i];
2722  ocs_memcpy(dst, src, sizeof(*src));
2723  }
2724 
2725  iscsi->num_ips--;
2726  rc = 0;
2727  }
2728 
2729  return rc;
2730 }
2731 
2732 
2733 /**
2734  * @brief Checks if an IP address/subnet is present in the table.
2735  *
2736  * @param ocs Pointer to the ocs structure.
2737  * @param ipsub Pointer to the IP address/subnet structure to check.
2738  *
2739  * @return Returns TRUE if the IP address is found.
2740  */
2741 int32_t
2743 {
2744  int32_t rc = FALSE;
2745  uint32_t i;
2746  ocs_ip_address_t ip;
2747  ocs_ip_address_t subnet;
2748  ocs_iscsi_t *iscsi = &ocs->iscsi;
2749 
2750  ocs_iscsi_ipsub_split(ipsub, &ip, &subnet);
2751  for (i = 0; i < iscsi->num_ips; i++) {
2752  ocs_iscsi_tgt_ip_t *api_ip = &iscsi->ip_info[i];
2753  if (memcmp(&api_ip->ip, &ip, sizeof(ip)) == 0 &&
2754  memcmp(&api_ip->subnet, &subnet, sizeof(subnet)) == 0) {
2755  rc = TRUE;
2756  break;
2757  }
2758  }
2759  return rc;
2760 }
2761 
2762 
2763 /**
2764  * @brief Sets the IP gateway address.
2765  *
2766  * @param ocs Pointer to the ocs structure that represents this device.
2767  * @param gateway IP address of the gateway.
2768  *
2769  * @return Returns 0 on success.
2770  */
2771 int32_t ocs_iscsi_gateway_set(ocs_t *ocs, ocs_ip_address_t *gateway)
2772 {
2773  ocs_iscsi_t *iscsi = &ocs->iscsi;
2774  int32_t rc;
2775  ocs_config_ctx_t* ctx;
2776  ocs_hal_ip_address_t hal_ip;
2777 
2779  if (ctx == NULL) {
2780  ocs_log_err(iscsi->os, "context is busy\n");
2781  rc = -1;
2782  } else {
2783  ocs_iscsi_convert_to_hal_ip(gateway, &hal_ip);
2784  rc = ocs_hal_portal_gateway_add(iscsi->hal,
2785  &hal_ip,
2787  ctx);
2788 
2789  if (rc) {
2790  ocs_log_test(iscsi->os, "failed setting gateway\n");
2791  } else {
2793  3 * 1000000);
2794  if (rc == 0) {
2795  if (ctx->status != 0 ||
2796  ctx->ext_status != 0) {
2797  rc = -1;
2798  ocs_log_test(iscsi->os, "setting gateway status 0x%x ext status 0x%x\n",
2799  ctx->status, ctx->ext_status);
2800  }
2801  }
2802  }
2804  }
2805 
2806  return rc;
2807 }
2808 
2809 /**
2810  * @brief Retrieves the default portal.
2811  *
2812  * @param ocs Pointer to the ocs structure that represents this device.
2813  *
2814  * @return Returns the default portal.
2815  */
2817 {
2818  ocs_iscsi_t *iscsi = &ocs->iscsi;
2819 
2820  return ocs_hal_portal_get_default(iscsi->hal);
2821 }
2822 
2823 /**
2824  * @brief Find IP address of interface handle
2825  * If IP address is found for given interface handle, copy to ip and subnet params.
2826  *
2827  * @return Returns TRUE if IP addresses are found for given interface handle,
2828  * otherwise FALSE
2829  */
2830 int32_t ocs_iscsi_portal_find_ip_address(ocs_t *ocs, ocs_hal_portal_t iface_handle,
2831  ocs_ip_address_t *ip,
2832  ocs_ip_address_t *subnet,
2833  uint16_t *tcp_port, int32_t *listening)
2834 {
2835  ocs_iscsi_t *iscsi = &ocs->iscsi;
2836  int32_t rc = FALSE;
2837  uint32_t i;
2838 
2839  for (i = 0; i < iscsi->num_ips; i++) {
2840  ocs_iscsi_tgt_ip_t *api_ip = &iscsi->ip_info[i];
2841  if (api_ip->portal == iface_handle) {
2842  ocs_memcpy(ip, &api_ip->ip, sizeof(*ip));
2843  ocs_memcpy(subnet, &api_ip->subnet, sizeof(*subnet));
2844  *tcp_port = api_ip->tcp_port;
2845  *listening = api_ip->listening;
2846  rc = TRUE;
2847  break;
2848  }
2849  }
2850 
2851  return rc;
2852 }
2853 
2854 /**
2855  * @brief Check and remove IP addresses of the corresponding interface
2856  *
2857  * @param ocs Pointer to the OCS context
2858  * @param iface_handle Interface handle to check for IP addresses
2859  *
2860  * @return Returns 0 on success, otherwise a negative value
2861  */
2863  ocs_hal_portal_t iface_handle)
2864 {
2865  int32_t rc = 0;
2866  ocs_ip_address_t ip;
2867  ocs_ip_address_t subnet;
2869  char ip_str[40];
2870  uint16_t tcp_port;
2871  int32_t listening;
2872 
2873  while (TRUE) {
2874  ocs_memset(&ip, 0, sizeof(ip));
2875  ocs_memset(&subnet, 0, sizeof(subnet));
2876  rc = ocs_iscsi_portal_find_ip_address(ocs, iface_handle, &ip, &subnet,
2877  &tcp_port, &listening);
2878  if (!rc) {
2879  ocs_log_debug(ocs, "IP's are not found for iface %d\n",
2880  iface_handle);
2881  break;
2882  }
2883 
2884  format_ip_address(ip.ip_type, ip.ip_address, ip_str, sizeof(ip_str));
2885  ocs_log_debug(ocs, "Found IP %s in iface %d\n", ip_str, iface_handle);
2886  /* Stop listening on the IP address */
2887  if (listening) {
2888  rc = ocs_iscsi_listen_stop(ocs, &ip, tcp_port);
2889  if (rc) {
2890  ocs_log_err(ocs, "Failed to stop listening on IP %s\n",
2891  ip_str);
2892  break;
2893  } else {
2894  ocs_log_debug(ocs, "Stopped listening on IP %s\n",
2895  ip_str);
2896  }
2897  }
2898 
2899  ocs_iscsi_ipsub_combine(&ipsub, &ip, &subnet);
2900  rc = ocs_iscsi_ip_address_remove(ocs, iface_handle, &ipsub);
2901  if (rc) {
2902  ocs_log_err(ocs, "Failed removing IP %s\n", ip_str);
2903  break;
2904  } else {
2905  ocs_log_debug(ocs, "Removed IP %s\n", ip_str);
2906  }
2907  }
2908 
2909  return rc;
2910 }
2911 
2912 /**
2913  * @brief Helper function to find respective interface handle of VLAN id
2914  *
2915  * @param ocs Pointer to the ocs structure that represents this device.
2916  * @param vlan_tag The vlan id
2917  * @param iface_handle
2918  *
2919  * @return Returns 0 if interface handle is found, otherwise a negative value.
2920  */
2921 int32_t ocs_iscsi_find_portal_from_vlan(ocs_t *ocs, uint32_t vlan_id,
2922  ocs_hal_portal_t *iface_handle)
2923 {
2924  iscsi_api_t *iscsi_api = ocs->iscsi_api;
2925  ocs_vlan_portal_info_t *portal;
2926  int32_t rc = -EFAULT;
2927 
2928  ocs_lock(&iscsi_api->api_list_lock);
2929  ocs_list_foreach(&iscsi_api->portal_list, portal) {
2930  if (portal->vlan_id == vlan_id) {
2931  *iface_handle = portal->iface_handle;
2932  rc = 0;
2933  break;
2934  }
2935  }
2936  ocs_unlock(&iscsi_api->api_list_lock);
2937 
2938  return rc;
2939 
2940 }
2941 /**
2942  * @brief Check VLAN for duplicate
2943  *
2944  * @param ocs Pointer to the ocs structure that represents this device.
2945  * @param vlan_tag The vlan to check for duplicates.
2946  *
2947  * @return Returns TRUE if VLAN is not exists, otherwise FALSE.
2948  */
2949 int32_t ocs_iscsi_portal_is_vlan_exists(ocs_t *ocs, uint32_t vlan_id)
2950 {
2951  iscsi_api_t *iscsi_api = ocs->iscsi_api;
2952  ocs_vlan_portal_info_t *portal;
2953  int32_t rc = FALSE;
2954 
2955  ocs_lock(&iscsi_api->api_list_lock);
2956  ocs_list_foreach(&iscsi_api->portal_list, portal) {
2957  if (portal->vlan_id == vlan_id) {
2958  rc = TRUE;
2959  break;
2960  }
2961  }
2962  ocs_unlock(&iscsi_api->api_list_lock);
2963 
2964  return rc;
2965 }
2966 
2967 /**
2968  * @brief Add VLAN and iface handle to portal_list
2969  *
2970  * @param ocs Pointer to the ocs structure that represents this device.
2971  * @param iface The interface handle to add
2972  * @param vlan_tag The vlan id to add
2973  *
2974  * @return Returns 0 on success, otherwise a negative value
2975  */
2977  uint32_t vlan_id)
2978 {
2979  iscsi_api_t *iscsi_api = ocs->iscsi_api;
2980  ocs_vlan_portal_info_t *portal;
2981 
2982  ocs_lock(&iscsi_api->api_list_lock);
2983 
2984  portal = ocs_malloc(ocs, sizeof(ocs_vlan_portal_info_t),
2985  OCS_M_ZERO | OCS_M_NOWAIT);
2986  if (portal == NULL) {
2987  ocs_log_err(ocs, "Failed to allocate memory\n");
2988  ocs_unlock(&iscsi_api->api_list_lock);
2989  return -ENOMEM;
2990  }
2991 
2992  portal->iface_handle = iface;
2993  portal->vlan_id = vlan_id;
2994  ocs_list_add_tail(&iscsi_api->portal_list, portal);
2995  ocs_log_debug(ocs, "Added portal %d and vlan %d to portal_list\n",
2996  iface, vlan_id);
2997 
2998  ocs_unlock(&iscsi_api->api_list_lock);
2999  return 0;
3000 }
3001 
3002 /**
3003  * @brief Delete iface handle and VLAN from portal_list
3004  *
3005  * @param ocs Pointer to the ocs structure that represents this device.
3006  * @param iface The interface handle to delete
3007  * @param vlan_tag The vlan id to delete
3008  *
3009  * @return Returns 0 on success, otherwise a negative value
3010  */
3012 {
3013  iscsi_api_t *iscsi_api = ocs->iscsi_api;
3014  ocs_vlan_portal_info_t *portal;
3015  ocs_vlan_portal_info_t *portal_next;
3016 
3017  ocs_lock(&iscsi_api->api_list_lock);
3018  ocs_list_foreach_safe(&iscsi_api->portal_list, portal, portal_next) {
3019  if (portal->iface_handle == iface) {
3020  ocs_log_debug(ocs, "Removing portal %d from portal_list\n",
3021  portal->iface_handle);
3022  ocs_list_remove(&iscsi_api->portal_list, portal);
3023  ocs_free(ocs, portal, sizeof(*portal));
3024  break;
3025  }
3026  }
3027  ocs_unlock(&iscsi_api->api_list_lock);
3028 
3029  return 0;
3030 }
3031 
3032 /**
3033  * @brief Read VLAN IDs to provided buffer.
3034  *
3035  * @param ocs Pointer to the ocs structure that represents this device.
3036  * @param arg_out Pointer to output buffer
3037  * @param arg_out_length Length of output buffer
3038  *
3039  * @return Returns 0 on success, otherwise a negative value
3040  */
3041 int32_t ocs_iscsi_portal_read_vlan_ids(ocs_t *ocs, void *arg_out,
3042  uint32_t arg_out_length)
3043 {
3044  int32_t ret = 0;
3045  iscsi_api_t *iscsi_api = ocs->iscsi_api;
3046  uint32_t remain = arg_out_length;
3047  char *userbuff = (char *)arg_out;
3048  uint32_t len = 0;
3049  uint32_t bytes_to_copy;
3050  ocs_vlan_portal_info_t *portal_info;
3051  ocs_vlan_portal_info_t *portal_next;
3052  char str[64];
3053 
3054  ocs_lock(&iscsi_api->api_list_lock);
3055  if (!ocs_list_empty(&iscsi_api->portal_list)) {
3056  ocs_list_foreach_safe(&iscsi_api->portal_list, portal_info, portal_next) {
3057  snprintf(str, sizeof(str), "VLAN id %d\n", portal_info->vlan_id);
3058  len = ocs_strlen(str);
3059  bytes_to_copy = (len > remain ? remain : len);
3060  if (ocs_copy_to_user(userbuff, str, bytes_to_copy)) {
3061  ret = -EFAULT;
3062  break;
3063  } else {
3064  userbuff += bytes_to_copy;
3065  remain -= bytes_to_copy;
3066  ret = 0;
3067  }
3068  }
3069  } else {
3070  snprintf(str, sizeof(str), "VLAN list is empty\n");
3071  len = ocs_strlen(str);
3072  bytes_to_copy = (len > remain ? remain : len);
3073  if (ocs_copy_to_user(userbuff, str, bytes_to_copy)) {
3074  ret = -EFAULT;
3075  } else {
3076  userbuff += bytes_to_copy;
3077  remain -= bytes_to_copy;
3078  ret = 0;
3079  }
3080  }
3081  ocs_unlock(&iscsi_api->api_list_lock);
3082 
3083  if (!ret) {
3084  ret = -EFAULT;
3085  if (remain > 1) {
3086  if (!ocs_copy_to_user(userbuff, "\0", 1)) {
3087  ret = 0;
3088  }
3089  }
3090  }
3091 
3092  return ret;
3093 }
3094 
3095 /**
3096  * @brief This function is the callback for creating an interface/portal
3097  *
3098  * @param ul_arg Pointer to the iscsi object.
3099  * @param status Status of the command.
3100  * @param ext_status Extended status of the command.
3101  * @param params NULL for this function.
3102  */
3103 static void ocs_iscsi_portal_create_cb(void *ul_arg,
3104  int32_t status,
3105  uint32_t ext_status,
3106  void *params)
3107 {
3108  ocs_config_ctx_t *ctx = ul_arg;
3109  ocs_hal_portal_t iface = (ocs_hal_portal_t)(uintptr_t)params;
3110 
3111  ctx->iface = iface;
3112  ocs_iscsi_ctx_post(ctx, status, ext_status);
3113 }
3114 
3115 
3116 /**
3117  * @brief Creates a portal for a VLAN
3118  *
3119  * @param ocs Pointer to the ocs structure that represents this device.
3120  * @param vlan_tag The vlan to create.
3121  * @param portal Portal to create.
3122  *
3123  * @return Returns 0 on success.
3124  */
3125 int32_t ocs_iscsi_portal_create(ocs_t *ocs, unsigned int vlan_id,
3126  ocs_hal_portal_t *portal)
3127 {
3128  ocs_iscsi_t *iscsi = &ocs->iscsi;
3129  int32_t rc;
3130  ocs_config_ctx_t* ctx;
3131 
3132  /* No need of having multiple interfaces with same vlan_id */
3133  rc = ocs_iscsi_portal_is_vlan_exists(ocs, vlan_id);
3134  if (rc) {
3135  ocs_log_err(ocs, "VLAN id %d is already exists\n");
3136  return rc;
3137  }
3138 
3140  if (ctx == NULL) {
3141  ocs_log_err(iscsi->os, "context is busy\n");
3142  rc = -1;
3143  } else {
3144  rc = ocs_hal_portal_create(iscsi->hal, vlan_id,
3146  ctx);
3147  if (rc) {
3148  ocs_log_err(iscsi->os, "failed creating portal\n");
3149  } else {
3151  3 * 1000000);
3152  if (rc == 0) {
3153  if (ctx->status == 0 &&
3154  ctx->ext_status == 0) {
3155  *portal = ctx->iface;
3156  } else {
3157  rc = -1;
3158  ocs_log_err(iscsi->os, "creating portal status 0x%x ext status 0x%x\n",
3159  ctx->status, ctx->ext_status);
3160  }
3161  }
3162  }
3164  }
3165 
3166  if (rc == 0) {
3167  /* Add VLAN and iface handle to vlan_list */
3168  ocs_iscsi_portal_add_vlan(ocs, *portal, vlan_id);
3169  }
3170 
3171  return rc;
3172 }
3173 
3174 
3175 /**
3176  * @brief Removes a previously-created portal.
3177  *
3178  * @param ocs Pointer to the ocs structure that represents this device.
3179  * @param portal Portal to remove.
3180  *
3181  * @return Returns 0 on success.
3182  */
3183 int32_t ocs_iscsi_portal_delete(ocs_t *ocs, ocs_hal_portal_t portal)
3184 {
3185  ocs_iscsi_t *iscsi = &ocs->iscsi;
3186  int32_t rc;
3187  ocs_config_ctx_t* ctx;
3188 
3190  if (ctx == NULL) {
3191  ocs_log_err(iscsi->os, "context is busy\n");
3192  rc = -1;
3193  } else {
3194  rc = ocs_hal_portal_delete(iscsi->hal, portal,
3196  ctx);
3197  if (rc) {
3198  ocs_log_test(iscsi->os, "failed creating portal\n");
3199  } else {
3201  3 * 1000000);
3202  if (rc == 0) {
3203  if (ctx->status != 0 ||
3204  ctx->ext_status != 0) {
3205  rc = -1;
3206  ocs_log_err(iscsi->os, "deleting portal status 0x%x ext status 0x%x\n",
3207  ctx->status, ctx->ext_status);
3208  }
3209  }
3210  }
3212  }
3213 
3214  return rc;
3215 }
3216 
3217 
3218 /**
3219  * @brief Starts a TCP listen socket.
3220  *
3221  * @param ocs Pointer to the ocs structure that represents this device.
3222  * @param ip IP address to listen on.
3223  * @param tcp_port TCP port number to listen on.
3224  *
3225  * @return Returns 0 on success.
3226  */
3228  uint16_t tcp_port)
3229 {
3230  ocs_iscsi_t *iscsi = &ocs->iscsi;
3231  int32_t rc;
3232  ocs_config_ctx_t* ctx;
3233  ocs_hal_ip_address_t hal_ip;
3234 
3236  if (ctx == NULL) {
3237  ocs_log_err(iscsi->os, "context is busy\n");
3238  rc = -1;
3239  } else {
3240  ocs_iscsi_convert_to_hal_ip(ip, &hal_ip);
3241  rc = ocs_hal_portal_listen_start(iscsi->hal,
3242  &hal_ip,
3243  tcp_port,
3245  ctx);
3246  if (rc) {
3247  ocs_log_test(iscsi->os, "failed Starting Listen\n");
3248  } else {
3250  3 * 1000000);
3251  if (rc == 0) {
3252  if (ctx->status != 0 ||
3253  ctx->ext_status != 0) {
3254  rc = -1;
3255  ocs_log_test(iscsi->os, "starting listen status 0x%x ext status 0x%x\n",
3256  ctx->status, ctx->ext_status);
3257  }
3258  }
3259  }
3261  }
3262 
3263  return rc;
3264 }
3265 
3266 /**
3267  * @brief Stops a TCP listen socket.
3268  *
3269  * @param ocs Pointer to the ocs structure that represents this device.
3270  * @param ip IP address to listen on.
3271  * @param tcp_port TCP port number to listen on.
3272  *
3273  * @return Returns 0 on success.
3274  */
3275 int32_t ocs_iscsi_listen_stop(ocs_t *ocs, ocs_ip_address_t *ip,
3276  uint16_t tcp_port)
3277 {
3278  ocs_iscsi_t *iscsi = &ocs->iscsi;
3279  int32_t rc;
3280  ocs_config_ctx_t* ctx;
3281  ocs_hal_ip_address_t hal_ip;
3282 
3284  if (ctx == NULL) {
3285  ocs_log_err(iscsi->os, "context is busy\n");
3286  rc = -1;
3287  } else {
3288  ocs_iscsi_convert_to_hal_ip(ip, &hal_ip);
3289  rc = ocs_hal_portal_listen_stop(iscsi->hal,
3290  &hal_ip,
3291  tcp_port,
3293  ctx);
3294  if (rc) {
3295  ocs_log_test(iscsi->os, "failed Stopping Listen\n");
3296  } else {
3298  3 * 1000000);
3299  if (rc == 0) {
3300  if (ctx->status != 0 ||
3301  ctx->ext_status != 0) {
3302  rc = -1;
3303  ocs_log_test(iscsi->os, "stopping listen status 0x%x ext status 0x%x\n",
3304  ctx->status, ctx->ext_status);
3305  }
3306  }
3307  }
3309  }
3310 
3311  return rc;
3312 }
3313 
3314 /**
3315  * @brief Register to receive link state change notifications.
3316  *
3317  * @par Description
3318  * This function is used by upper level drivers to register a
3319  * function which should be called when the link state changes.
3320  *
3321  * @return Returns 0 on success, or a negative error code value
3322  * on failure.
3323  */
3325 {
3326  ocs_iscsi_t *iscsi = &ocs->iscsi;
3327  uint32_t i;
3328 
3329  /* Check to see if we already have this callback registered */
3330  for (i=0; i<OCS_ISCSI_MAX_LINK_STATE_CALLBACKS; i++) {
3331  if (iscsi->link_state_callbacks[i] == cb) {
3332  /* Already registered */
3333  return 0;
3334  }
3335  }
3336 
3337  ocs_lock(&iscsi->link_state_cb_lock);
3338  for (i=0; i<OCS_ISCSI_MAX_LINK_STATE_CALLBACKS; i++) {
3339  if (iscsi->link_state_callbacks[i] == NULL) {
3340  iscsi->link_state_callbacks[i] = cb;
3341  break;
3342  }
3343  }
3344  ocs_unlock(&iscsi->link_state_cb_lock);
3345 
3346 
3347  return 0;
3348 
3349 }
3350 
3351 /**
3352  * @brief Unregister a link state change callback.
3353  *
3354  * @par Description
3355  * This function is used by upper level drivers to remove the
3356  * registration of a link state callback function.
3357  *
3358  * @return None.
3359  */
3361 {
3362  ocs_iscsi_t *iscsi = &ocs->iscsi;
3363  uint32_t i;
3364 
3365  ocs_lock(&iscsi->link_state_cb_lock);
3366  for (i=0; i<OCS_ISCSI_MAX_LINK_STATE_CALLBACKS; i++) {
3367  if (iscsi->link_state_callbacks[i] == cb) {
3368  iscsi->link_state_callbacks[i] = NULL;
3369  break;
3370  }
3371  }
3372  ocs_unlock(&iscsi->link_state_cb_lock);
3373 
3374 }
3375 
3376 /**
3377  * @brief Function to receive the notification of link events.
3378  *
3379  * @param arg Pointer to the iSCSI structure that represents this device.
3380  * @param isLinkUp Non-zero means the link is up.
3381  *
3382  * @return Returns 0 on success.
3383  */
3384 static int32_t
3385 ocs_iscsi_link_event_cb(void *arg, uint8_t isLinkUp)
3386 {
3387  ocs_iscsi_t *iscsi = (ocs_iscsi_t *)arg;
3388  ocs_t *ocs = iscsi->os;
3389  uint32_t i;
3390  ocs_link_state_e link_state;
3391 
3392  ocs_log_debug(iscsi->os, "link is %s\n", (isLinkUp ? "UP" : "DOWN"));
3393 
3394  link_state = (isLinkUp ? OCS_LINK_STATE_UP : OCS_LINK_STATE_DOWN);
3395 
3396  for (i=0; i<OCS_ISCSI_MAX_LINK_STATE_CALLBACKS; i++) {
3397  if (iscsi->link_state_callbacks[i] != NULL) {
3398  iscsi->link_state_callbacks[i](ocs, link_state);
3399  }
3400  }
3401 
3402 
3403  return 0;
3404 }
3405 
3406 
3407 #if defined(OCS_INCLUDE_DEBUG)
3408 /**
3409  * @brief Function to find and dump the WQE associated with an IO.
3410  *
3411  * @param iscsi Pointer to the iSCSI structure that represents this device.
3412  * @param io Pointer to the IO structure.
3413  */
3414 static void
3415 ocs_iscsi_dump_io(ocs_iscsi_t *iscsi,
3416  ocs_io_t *io)
3417 {
3418  ocs_cxn_t *cxn = io->node;
3419  sli4_queue_t *q = &iscsi->hal->wq[cxn->wq_index];
3420  sli4_wqe_context_t *ctx;
3421  char dmphdr[32];
3422 
3423  ocs_log_debug(iscsi->os, "%s ICD %d, ITT 0x%x, dsl=0x%x, wire_xfer_size=0x%x, wire_offset=0x%x, sge_offset=0x%x\n",
3424  (io->is_read ? "Read" : "Write"),
3425  (io->hio != NULL ? io->hio->icd : -1),
3426  io->init_task_tag,
3427  io->exp_xfer_len,
3428  io->scsi_wire_xfer_size,
3429  io->scsi_wire_offset,
3430  (io->hio != NULL ? io->hio->sge_offset : 0xFFFFFFFF));
3431 
3432  /* data = io->sgl; */
3433  /* for (index = 0; index < io->n_sge; index++) { */
3434  /* ocs_log_debug(iscsi->os, " sge %d 0x%x 0x%08x len=0x%x\n", */
3435  /* index, */
3436  /* data[index].buffer_address_high, */
3437  /* data[index].buffer_address_low, */
3438  /* data[index].buffer_length); */
3439  /* } */
3440 
3441  ocs_lock(&q->lock);
3442  ctx = ocs_list_get_head(&q->u.wq.wqe_busy);
3443  while (ctx != NULL) {
3444  if (ctx->io != NULL &&
3445  ctx->io == io) {
3446  uint8_t *qe = q->dma.virt + (ctx->wrb_index * q->size);
3447 
3448  ocs_snprintf(dmphdr, sizeof(dmphdr), "Io WQE Index %d", ctx->wrb_index);
3449  ocs_dump32(OCS_DEBUG_ALWAYS, iscsi->os, dmphdr, qe, q->size);
3450  break;
3451  }
3452  ctx = ocs_list_next(&q->u.wq.wqe_busy, ctx);
3453  }
3454  ocs_unlock(&q->lock);
3455 }
3456 
3457 /**
3458  * @brief Function to dump the active IOs on a connection.
3459  *
3460  * @param iscsi Pointer to the iSCSI structure that represents this device.
3461  * @param cxn Pointer to the connection object.
3462  */
3463 static void
3464 ocs_iscsi_dump_active_ios(ocs_iscsi_t *iscsi,
3465  ocs_cxn_t *cxn)
3466 {
3467  ocs_io_t *io;
3468  /* sli4_sge_t *data; */
3469  /* uint32_t index; */
3470 
3471  ocs_node_lock(cxn);
3472  ocs_list_foreach(&cxn->active_ios, io) {
3473  ocs_iscsi_dump_io(iscsi, io);
3474  }
3475  ocs_node_unlock(cxn);
3476 }
3477 #endif
3478 
3479 
3480 /**
3481  * @brief Function to process connection invalidation notifications.
3482  *
3483  * @param iscsi Pointer to the iSCSI structure that represents this device.
3484  * @param cxn Pointer to the connection object.
3485  * @param code Error code.
3486  *
3487  * @return Returns 0 on success.
3488  */
3489 static int32_t
3491  ocs_cxn_t *cxn,
3492  uint32_t code)
3493 {
3494  int32_t rc = 0;
3495  uint8_t sendRst = code != SLI_STATUS_RECV_TCP_FIN;
3496 
3497  ocs_log_debug(iscsi->os, "Cxn %p with wq_id 0x%x conn_hdl 0x%x for %s Invalidated in FW (0x%x)\n",
3498  cxn,
3499  cxn->wq_id,
3500  cxn->conn_hdl,
3501  cxn->display_name,
3502  code);
3503 #if defined(OCS_INCLUDE_DEBUG)
3504  ocs_iscsi_dump_active_ios(iscsi, cxn);
3505 #endif
3506 
3507  if (cxn->cxn_state == CONN_STATE_FULL_FEATURE) {
3508  switch(code) {
3521  if (!cxn->is_ini_cxn) {
3522  ocs_log_test(iscsi->os, "CQE with code %d - send async logout for %s\n",
3523  code, cxn->display_name);
3524  rc = ocs_iscsi_cxn_request_logout(cxn);
3525  if (rc != 0) {
3526  ocs_log_test(iscsi->os, "Request logout status %d for %s\n",
3527  rc, cxn->display_name);
3528  }
3529  } else {
3530  ocs_log_test(iscsi->os, "CQE with code %d on ini cxn %s - close\n",
3531  code, cxn->display_name);
3532  }
3533  ocs_cxn_close(cxn, FALSE);
3534  break;
3535  default:
3536  rc = ocs_cxn_close(cxn, sendRst);
3537  break;
3538  }
3539  } else {
3540  rc = ocs_cxn_close(cxn, sendRst);
3541  }
3542 
3543  return rc;
3544 }
3545 
3546 /**
3547  * @brief Function to process a data digest error.
3548  *
3549  * @param iscsi Pointer to the iSCSI structure that represents this device.
3550  * @param tgt_digest Pointer to the data digest error fields.
3551  *
3552  * @return Returns 0 on success.
3553  */
3554 static int32_t
3556  ocs_hal_tgt_data_digest_t *tgt_digest)
3557 {
3558  ocs_cxn_t *cxn = tgt_digest->cxn;
3559  ocs_hal_io_t *hio = tgt_digest->io;
3560  ocs_io_t *io = tgt_digest->arg;
3561  int32_t rc = -1;
3563 
3564  ocs_log_debug(iscsi->os, "data digest error on cid %d, icd %d\n",
3565  cxn->wq_id,
3566  (hio == NULL ? -1 : hio->icd));
3567 
3568  if (hio != NULL) {
3569  /*
3570  * We have to rebuild the header from the provided fields so that
3571  * we can send the reject PDU!
3572  */
3573  ocs_memset(&hdr, 0, sizeof(iscsi_data_out_hdr_t));
3574  hdr.final = tgt_digest->fin;
3575  hdr.opcode = ISCSI_CMD_DATA_OUT;
3576  hdr.dw2.data_segment_length[0] = (tgt_digest->data_seg_length >> 16) & 0xff;
3577  hdr.dw2.data_segment_length[1] = (tgt_digest->data_seg_length >> 8) & 0xff;
3578  hdr.dw2.data_segment_length[2] = tgt_digest->data_seg_length & 0xff;
3579  hdr.lun.lun_64 = io->iscsi_lun; /* already in BE */
3580  hdr.itt = ocs_htobe32(io->init_task_tag);
3581  hdr.ttt = ocs_htobe32(hio->ttt);
3582  hdr.exp_status_sn = ocs_htobe32(tgt_digest->exp_statsn);
3583  hdr.data_sn = ocs_htobe32(tgt_digest->datasn);
3584  hdr.buffer_offset = ocs_htobe32(tgt_digest->buffer_offset);
3585 
3586  rc = ocs_iscsi_send_reject(cxn, &hdr, sizeof(iscsi_data_out_hdr_t),
3588  }
3589  return rc;
3590 }
3591 
3592 /**
3593  * @brief Function to receive connection events.
3594  *
3595  * @param arg Pointer to the iSCSI structure that represents this device.
3596  * @param cxn_event Identifies the event that was received.
3597  *
3598  * @return Returns 0 on success.
3599  */
3600 static int32_t
3602 {
3603  ocs_iscsi_t *iscsi = (ocs_iscsi_t *)arg;
3604  int32_t rc = -1;
3605 
3606  switch(cxn_event->event) {
3607  case OCS_HAL_CXN_NEW:
3608  rc = ocs_cxn_new_tgt_connection(iscsi, cxn_event->params.cxn_new.cid);
3609  break;
3610 
3611  case OCS_HAL_CXN_INVALID:
3612  rc = ocs_iscsi_cxn_event_invalid(iscsi,
3613  cxn_event->params.cxn_invalid.cxn,
3614  cxn_event->params.cxn_invalid.code);
3615  break;
3616 
3619  &cxn_event->params.tgt_digest);
3620  break;
3621 
3622  default:
3623  ocs_log_test(iscsi->os, "Unhandled cxn event received %d\n",
3624  cxn_event->event);
3625  break;
3626  }
3627 
3628  return rc;
3629 }
3630 
3631 
3632 /**
3633  * @brief Decode a LU Number according to SAM.
3634  *
3635  * @param lu Pointer to LU data
3636  *
3637  * @note Only handles single level LU.
3638  *
3639  * @todo Move to generic FC file.
3640  *
3641  * @return Returns LU number or max int on error.
3642  */
3643 static uint32_t
3645 {
3646  uint32_t lun = UINT32_MAX;
3647  uint8_t address_method = -1;
3648 
3649  address_method = lu[0] >> ISCSI_LUN_ADDRESS_METHOD_SHIFT;
3650 
3651  switch (address_method) {
3653  {
3654  uint8_t bus_identifier = lu[0] & ~ISCSI_LUN_ADDRESS_METHOD_MASK;
3655 
3656  if (0 == bus_identifier) {
3657  lun = lu[1];
3658  } else {
3659  ocs_log_test(NULL, "unsupported bus identifier %#02x (LU %02x %02x %02x %02x ...\n",
3660  bus_identifier, lu[0], lu[1], lu[2], lu[3]);
3661  }
3662  break;
3663  }
3665  {
3666  lun = (lu[0] & ~ISCSI_LUN_ADDRESS_METHOD_MASK) << 8 | lu[1];
3667  break;
3668  }
3670  {
3671  uint8_t length, extended_address_method;
3672 
3673  length = (lu[0] & 0x30) >> 4;
3674  extended_address_method = lu[0] & 0xf;
3675 
3676  if ((1 == length) && (2 == extended_address_method)) {
3677  lun = (lu[1] << 16) | (lu[2] << 8) | lu[3];
3678  } else {
3679  ocs_log_test(NULL, "unsupported extended addressing method (length=%#x method=%#x)\n",
3680  length, extended_address_method);
3681  }
3682  break;
3683  }
3684  default:
3685  ocs_log_test(NULL, "unsupported LU address method %#02x\n", address_method);
3686  }
3687 
3688  return lun;
3689 }
3690 
3691 
3692 /**
3693  * @brief Function to receive unsolicited command PDUs.
3694  *
3695  * @param iscsi Pointer to the iSCSI structure that represents this device.
3696  * @param cxn Pointer to the connection object.
3697  * @param hdr DMA memory information for the header.
3698  * @param hdr_len Length of the header received.
3699  * @param data DMA memory information for the data.
3700  * @param data_len Length of the data received.
3701  *
3702  * @return Returns 0 on success.
3703  */
3704 static ocs_pdu_process_rtn_e
3706  ocs_cxn_t *cxn,
3707  ocs_hal_rq_buffer_t *hdr,
3708  uint32_t hdr_len,
3709  ocs_hal_rq_buffer_t *data,
3710  uint32_t data_len)
3711 {
3712  ocs_t *ocs = iscsi->os;
3713  iscsi_cmd_hdr_t *cmd_hdr = hdr->dma.virt;
3714  ocs_io_t *io;
3715  uint32_t flags = 0;
3716  //uint32_t exp_xfer_len = 0;
3718  uint32_t imm_length;
3719  uint32_t lun;
3720 
3721  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
3722  ocs_log_test(iscsi->os, "called with connection state %d",
3723  cxn->cxn_state);
3724  ocs_cxn_close(cxn, TRUE);
3726  }
3727 
3728  //exp_xfer_len = ocs_be32toh(cmd_hdr->ExpectedDataTransferLength);
3729 
3731 
3732  if (io != NULL) {
3733  io->cmd_sn = ocs_be32toh(cmd_hdr->CmdSN);
3734  io->init_task_tag = ocs_be32toh(cmd_hdr->itt);
3735  io->exp_xfer_len = ocs_be32toh(cmd_hdr->ExpectedDataTransferLength);
3736  io->iscsi_lun = cmd_hdr->lun.lun_64;
3737  lun = ocs_iscsi_decode_lun(cmd_hdr->lun.lun_8);
3738 
3739  switch(cmd_hdr->attributes) {
3740  case ISCSI_UNTAGGED_TAG:
3741  flags |= OCS_SCSI_CMD_UNTAGGED;
3742  break;
3743  case ISCSI_SIMPLE_TAG:
3744  flags |= OCS_SCSI_CMD_SIMPLE;
3745  break;
3747  flags |= OCS_SCSI_CMD_ORDERED;
3748  break;
3750  flags |= OCS_SCSI_CMD_HEAD_OF_QUEUE;
3751  break;
3752  case ISCSI_ACA_TAG:
3753  flags |= OCS_SCSI_CMD_ACA;
3754  break;
3755  default:
3756  break;
3757  }
3758  if (cmd_hdr->wr) {
3759  flags |= OCS_SCSI_CMD_DIR_IN;
3760  }
3761  if (cmd_hdr->rd) {
3762  flags |= OCS_SCSI_CMD_DIR_OUT;
3763  }
3764 
3765  //TODO Handle immediate data with DIF
3766  io_trace(io, "IO started (instance%d)\n", io->instance_index);
3767 
3768  /*
3769  * Note: The ocs_scsi_recv_cmd will return an error when it sees an
3770  * inquiry for a non-existent lun. We don't want this to drop
3771  * the connection, so ignore the return code here.
3772  */
3773  if (ocs_is_target_enabled()) {
3774  if (data_len > 0 &&
3775  data != NULL) {
3776  imm_length = ((uint32_t)cmd_hdr->dw2.data_segment_length[0] << 16) |
3777  ((uint32_t)cmd_hdr->dw2.data_segment_length[1] << 8) |
3778  cmd_hdr->dw2.data_segment_length[2];
3779  io->scsi_mem_xfer_size = imm_length;
3780  io->scsi_mem_offset = imm_length;
3781  io->scsi_wire_xfer_size = imm_length;
3782  io->scsi_wire_offset = imm_length;
3783 
3785  lun,
3786  cmd_hdr->cdb,
3787  16,
3788  flags,
3789  &data->dma,
3790  imm_length);
3791  } else {
3792  ocs_scsi_recv_cmd(io,
3793  lun,
3794  cmd_hdr->cdb,
3795  16,
3796  flags);
3797  }
3798  }
3799  } else {
3800  ocs_log_test(iscsi->os, "No IO object on connection %s, dropping command\n",
3801  cxn->display_name);
3803  }
3804  return rc;
3805 }
3806 
3807 /**
3808  * @brief Callback function used to free an IO for a rejected task management function.
3809  *
3810  * @param io Pointer to the OS io object.
3811  * @param status Status of the command.
3812  * @param flags Flags.
3813  * @param arg Points to the io object.
3814  *
3815  * @return Returns 0 on success.
3816  */
3817 /* Callback used by send_rd_data(), recv_wr_data(), send_resp() */
3818 static int32_t ocs_iscsi_recv_tm_cb(ocs_io_t *io, ocs_scsi_io_status_e status,
3819  uint32_t flags, void *arg)
3820 {
3821  /* This is used for rejected TMF functions, just free the IOs. */
3822  ocs_scsi_io_free(io);
3823  return 0;
3824 }
3825 
3826 
3827 /**
3828  * @brief Function to receive unsolicited task management PDUs.
3829  *
3830  * @param iscsi Pointer to the iSCSI structure that represents this device.
3831  * @param cxn Pointer to the connection object.
3832  * @param hdr DMA memory information for the header.
3833  * @param hdr_len Length of the header received.
3834  *
3835  * @return Returns 0 on success.
3836  */
3837 static ocs_pdu_process_rtn_e
3839  ocs_cxn_t *cxn,
3840  ocs_hal_rq_buffer_t *hdr,
3841  uint32_t hdr_len)
3842 {
3843  ocs_t *ocs = iscsi->os;
3844  iscsi_task_mgmt_hdr_t *tm_hdr = hdr->dma.virt;
3845  ocs_io_t *io;
3847  ocs_scsi_tmf_cmd_e tmf_cmd;
3848  ocs_io_t *abortio = NULL;
3849  ocs_io_t *listio;
3850  uint32_t cmd_sn = ocs_be32toh(tm_hdr->cmd_sn);
3851  uint32_t reftag = ocs_be32toh(tm_hdr->ref_task_tag);
3852  uint32_t refcmdsn = ocs_be32toh(tm_hdr->ref_cmd_sn);
3853  uint32_t lun;
3854 
3855  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
3856  ocs_log_test(iscsi->os, "called with connection state %d",
3857  cxn->cxn_state);
3858  ocs_cxn_close(cxn, TRUE);
3860  }
3861 
3863  if (io != NULL) {
3864  io->init_task_tag = ocs_be32toh(tm_hdr->itt);
3865  io->iscsi_lun = tm_hdr->lun.lun_64;
3866  lun = ocs_iscsi_decode_lun(tm_hdr->lun.lun_8);
3867 
3868  if (ocs_is_target_enabled()) {
3869  ocs_log_debug(iscsi->os, "TM (instance%d) started for ITT 0x%x, ref ITT 0x%x\n",
3870  io->instance_index, io->init_task_tag, reftag);
3871 
3872  switch (tm_hdr->function) {
3873  case ISCSI_ABORT_TASK:
3874  tmf_cmd = OCS_SCSI_TMF_ABORT_TASK;
3875  /* lookup IO to abort via the reference task tag */
3876  ocs_node_lock(cxn);
3877  ocs_list_foreach(&cxn->active_ios, listio) {
3878  if (listio->init_task_tag == reftag &&
3879  (listio->cmd_sn == refcmdsn ||
3880  cmd_sn == refcmdsn)) {
3881  abortio = listio;
3882  break;
3883  }
3884  }
3885  ocs_node_unlock(cxn);
3886 
3887  /* Complete the request if the IO is not found (SAM) */
3888  if (abortio == NULL) {
3889  int32_t rc;
3890  rc = ocs_session_abort_itt(cxn->session, reftag);
3892  (io,
3895  ocs_iscsi_recv_tm_cb, io);
3896  return OCS_PDU_RTN_PROCESSED;
3897  } else {
3898 #if defined(OCS_INCLUDE_DEBUG)
3899  ocs_iscsi_dump_io(iscsi, abortio);
3900 #endif
3901  }
3902  break;
3903  case ISCSI_ABORT_TASK_SET:
3904  ocs_session_abort_cmdsn(cxn->session, cmd_sn);
3905  tmf_cmd = OCS_SCSI_TMF_ABORT_TASK_SET;
3906  break;
3907  case ISCSI_CLEAR_ACA:
3908  tmf_cmd = OCS_SCSI_TMF_CLEAR_ACA;
3909  break;
3910  case ISCSI_CLEAR_TASK_SET:
3911  ocs_session_abort_cmdsn(cxn->session, cmd_sn);
3912  tmf_cmd = OCS_SCSI_TMF_CLEAR_TASK_SET;
3913  break;
3914  case ISCSI_LUN_RESET:
3915  /* Abort queued commands on all active sessions */
3916  ocs_session_all_abort_cmdsn(iscsi, cmd_sn);
3918  break;
3921  case ISCSI_TASK_REASSIGN:
3922  default:
3923  rc = ocs_iscsi_send_tmf_resp(io,
3926  io);
3927  return (rc == 0 ? OCS_PDU_RTN_PROCESSED : OCS_PDU_RTN_GENERAL_ERROR);
3928  }
3929 
3930  ocs_scsi_recv_tmf(io,
3931  lun,
3932  tmf_cmd,
3933  abortio,
3934  0);
3935  }
3936  } else {
3937  ocs_log_test(iscsi->os, "No IO object on connection %s, dropping TM\n",
3938  cxn->display_name);
3940  }
3941  return rc;
3942 }
3943 
3944 
3945 /**
3946  * @brief Function to receive unsolicited task management response PDUs.
3947  *
3948  * @param iscsi Pointer to the iSCSI structure that represents this device.
3949  * @param cxn Pointer to the connection object.
3950  * @param hdr DMA memory information for the header.
3951  * @param hdr_len Length of the header received.
3952  *
3953  * @return Returns 0 on success.
3954  */
3955 static int32_t
3957  ocs_cxn_t *cxn,
3958  ocs_hal_rq_buffer_t *hdr,
3959  uint32_t hdr_len)
3960 {
3961  iscsi_task_mgmt_response_t *tm_hdr = hdr->dma.virt;
3962  uint32_t itt = ocs_be32toh(tm_hdr->itt);
3963  ocs_io_t *io = NULL, *tmp_io;
3964  ocs_scsi_cmd_resp_t rsp;
3966  int32_t rc = 0;
3967 
3968  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
3969  ocs_log_test(iscsi->os, "called with connection state %d",
3970  cxn->cxn_state);
3971  ocs_cxn_close(cxn, TRUE);
3972  return -1;
3973  }
3974 
3975  /*
3976  * Loop through the active IOs on this node to find the matching ITT.
3977  */
3978  ocs_node_lock(cxn);
3979  ocs_list_foreach(&cxn->active_ios, tmp_io) {
3980  if (tmp_io->hio != NULL &&
3981  tmp_io->hio->itt == itt) {
3982  io = tmp_io;
3983  break;
3984  }
3985  }
3986  ocs_node_unlock(cxn);
3987 
3988  if (io) {
3989  ocs_assert(io->scsi_io_cb, -1);
3990 
3991  /* Clear the idle count */
3992  cxn->idle_count = 0;
3993 
3994  /* Call initiator server completion */
3995  if (io->scsi_io_cb) {
3996  uint32_t flags = 0;
3998 
3999  ocs_memset(&rsp, 0, sizeof(ocs_scsi_cmd_resp_t));
4000 
4002  rsp.scsi_status = 0;
4003  cb_status = OCS_SCSI_STATUS_GOOD;
4004  } else {
4005  rsp.scsi_status = 2;
4006  cb_status = OCS_SCSI_STATUS_ERROR;
4007  }
4008 
4009  cb = io->scsi_io_cb;
4010 
4011  /* Clear the callback before invoking the callback */
4012  io->scsi_io_cb = NULL;
4013 
4014  io_trace(io, "TM IO completed with status 0x%x (flags 0x%x)\n",
4015  cb_status, flags);
4016 
4017  cb(io, cb_status, &rsp, flags, io->scsi_io_cb_arg);
4018  }
4019  } else {
4020  rc = -1;
4021  ocs_log_test(iscsi->os, "IO with ITT was not found 0x%x", itt);
4022  }
4023  return rc;
4024 }
4025 
4026 
4027 /**
4028  * @brief Function to process unsolicited PDUs for a target.
4029  *
4030  * @param iscsi Pointer to the iSCSI structure that represents this device.
4031  * @param cxn Pointer to the connection object.
4032  * @param hdr DMA memory information for the header.
4033  * @param hdr_len Length of the header received.
4034  * @param data DMA memory information for the data.
4035  * @param data_len Length of the data received.
4036  * @param code Type of callback received from the chip (i.e. SLI_STATUS_UNSOL_DATA_DIGEST_ERROR).
4037  * @param reject_reason Returns the reject reason.
4038  *
4039  * @return Returns 0 on success.
4040  */
4043  ocs_cxn_t *cxn,
4044  ocs_hal_rq_buffer_t *hdr,
4045  uint32_t hdr_len,
4046  ocs_hal_rq_buffer_t *data,
4047  uint32_t data_len,
4048  uint8_t code,
4049  uint8_t *reject_reason)
4050 {
4051  iscsi_login_cmd_hdr_t *bhs = hdr->dma.virt;
4053 
4054  *reject_reason = 0;
4055  switch (bhs->opcode) {
4056  case ISCSI_CMD_CMD:
4057  rc = ocs_iscsi_recv_cmd(iscsi,
4058  cxn,
4059  hdr,
4060  hdr_len,
4061  data,
4062  data_len);
4063  break;
4064 
4065  case ISCSI_CMD_TASK:
4066  rc = ocs_iscsi_recv_tm(iscsi, cxn, hdr, hdr_len);
4067  break;
4068 
4069  case ISCSI_CMD_NOOP:
4070  rc = ocs_iscsi_recv_nop_out(cxn, hdr, hdr_len, data, data_len);
4071  break;
4072 
4073  case ISCSI_CMD_LOGIN:
4074  rc = ocs_iscsi_recv_login(cxn, hdr, hdr_len, data, data_len);
4075  break;
4076 
4077  case ISCSI_CMD_TEXT:
4078  rc = ocs_iscsi_recv_text(cxn, hdr, hdr_len, data, data_len, reject_reason);
4079  break;
4080 
4081  case ISCSI_CMD_LOGOUT:
4082  rc = ocs_iscsi_recv_logout(cxn, hdr, hdr_len);
4083  break;
4084 
4085  case ISCSI_CMD_SNACK:
4086  *reject_reason = ISCSI_REJECT_REASON_SNACK_REJECT;
4088  break;
4089 
4090  case ISCSI_CMD_DATA_OUT:
4091  default:
4092  ocs_log_test(iscsi->os, "received unexpected OPCODE 0x%x", bhs->opcode);
4093  *reject_reason = ISCSI_REJECT_REASON_PROTOCOL_ERR;
4095  break;
4096  }
4097 
4098  return rc;
4099 }
4100 
4101 
4102 /**
4103  * @brief Function to receive unsolicited PDUs for an initiator.
4104  *
4105  * @param iscsi Pointer to the iSCSI structure that represents this device.
4106  * @param cxn Pointer to the connection object.
4107  * @param hdr DMA memory information for the header.
4108  * @param hdr_len Length of the header received.
4109  * @param data DMA memory information for the data.
4110  * @param data_len Length of the data received.
4111  * @param code Type of callback received from the chip (i.e. SLI_STATUS_UNSOL_DATA_DIGEST_ERROR).
4112  *
4113  * @return Returns 0 on success.
4114  */
4115 static int32_t
4117  ocs_cxn_t *cxn,
4118  ocs_hal_rq_buffer_t *hdr,
4119  uint32_t hdr_len,
4120  ocs_hal_rq_buffer_t *data,
4121  uint32_t data_len,
4122  uint8_t code)
4123 {
4124  ocs_t *ocs = iscsi->os;
4125  iscsi_login_cmd_hdr_t *bhs = hdr->dma.virt;
4126  int32_t rc = 0;
4127 
4128  if ((cxn->cxn_state == CONN_STATE_NEW_CONN ||
4129  cxn->cxn_state == CONN_STATE_LOGIN_PROGRESS) &&
4130  bhs->opcode != ISCSI_RESP_LOGIN) {
4131  ocs_log_test(iscsi->os,
4132  "startup connection rcvd opcode 0x%x instead of login resp, state=%u",
4133  bhs->opcode,
4134  cxn->cxn_state);
4135  ocs_iscsi_rx_buffers_free(iscsi, hdr, data);
4136  ocs_cxn_close(cxn, TRUE);
4137  return -1;
4138  }
4139 
4140  /* Clear the idle count */
4141  cxn->idle_count = 0;
4142 
4143  /*
4144  * The statSn processing is handled in the FW, so we only have to capture
4145  * the value on the final login response.
4146  *
4147  * The command window will be typically handled in the normal IO completion
4148  * path, so ignore it for now as it should only be for login, which is all
4149  * done with the immediate bit set.
4150  */
4151 
4152  switch (bhs->opcode) {
4153  case ISCSI_RESP_LOGIN:
4154  rc = ocs_iscsi_recv_login_rsp(cxn, hdr, hdr_len, data, data_len);
4155  if (ocs_is_initiator_enabled()) {
4156  if (rc == 0 &&
4157  cxn->cxn_state == CONN_STATE_FULL_FEATURE) {
4158  if (ocs_scsi_new_target((ocs_node_t *) cxn)) {
4159  ocs_log_test(iscsi->os, "CID 0x%x failed adding target to initiator server\n",
4160  cxn->conn_hdl);
4161  } else {
4162  ocs_log_debug(iscsi->os, "ocs_scsi_new_target() success\n");
4163  }
4164  }
4165  }
4166  break;
4167 
4168  case ISCSI_RESP_NOOP:
4169  rc = ocs_iscsi_recv_nop_in(cxn, hdr, hdr_len, data, data_len);
4170  break;
4171 
4172  case ISCSI_RESP_LOGOUT:
4173  rc = ocs_iscsi_recv_logout_rsp(cxn, hdr, hdr_len);
4174  break;
4175 
4176  case ISCSI_RESP_TASK:
4177  rc = ocs_iscsi_recv_tm_rsp(iscsi, cxn, hdr, hdr_len);
4178  break;
4179 
4180  case ISCSI_RESP_TEXT:
4181  case ISCSI_RESP_ASYNC:
4182  case ISCSI_RESP_REJECT:
4183  case ISCSI_RESP_RESP:
4184  case ISCSI_RESP_R2T:
4185  case ISCSI_RESP_DATAIN:
4186  default:
4187  ocs_log_test(iscsi->os, "received unexpected OPCODE 0x%x", bhs->opcode);
4188  rc = -1;
4189  break;
4190  }
4191 
4192  return rc;
4193 }
4194 
4195 
4196 /**
4197  * @brief Function to receive unsolicited PDUs.
4198  *
4199  * @param arg Pointer to the iSCSI structure that represents this device.
4200  * @param cxn Pointer to the connection object.
4201  * @param hdr DMA memory information for the header.
4202  * @param hdr_len Length of the header received.
4203  * @param data DMA memory information for the data.
4204  * @param data_len Length of the data received.
4205  * @param code Type of callback received from the chip (i.e. SLI_STATUS_UNSOL_DATA_DIGEST_ERROR).
4206  *
4207  * @return Returns 0 on success.
4208  */
4209 static int32_t
4211  ocs_cxn_t *cxn,
4212  ocs_hal_rq_buffer_t *hdr,
4213  uint32_t hdr_len,
4214  ocs_hal_rq_buffer_t *data,
4215  uint32_t data_len,
4216  uint8_t code)
4217 {
4218  ocs_iscsi_t *iscsi = (ocs_iscsi_t *)arg;
4219  int32_t rc = 0;
4220  ocs_assert(cxn, -1);
4221  ocs_assert(hdr, -1);
4222 
4223  if (cxn->is_ini_cxn) {
4224  /* If there is an initiator unsol handler call that */
4225  if (iscsi->unsol_ini) {
4226  return iscsi->unsol_ini(arg, cxn, hdr, hdr_len, data, data_len, code);
4227  } else {
4229  cxn,
4230  hdr,
4231  hdr_len,
4232  data,
4233  data_len,
4234  code);
4235  }
4236  } else {
4238  hdr,
4239  hdr_len,
4240  data,
4241  data_len,
4242  code);
4243  }
4244 
4245  if (rc != OCS_LOGIN_REQUEST_QUEUED) {
4246  ocs_iscsi_rx_buffers_free(iscsi, hdr, data);
4247  }
4248 
4249  /* close the connection on any errors */
4250  if (rc &&
4251  rc != OCS_LOGIN_REQUEST_QUEUED) {
4252  ocs_log_test(iscsi->os, "Error processing unsolicited PDU\n");
4253  if (cxn->is_ini_cxn) {
4255  } else {
4256  rc = ocs_iscsi_cxn_request_logout(cxn);
4257  }
4258 
4259  /* Close the connection if we can't logout/request logout */
4260  if (rc &&
4261  rc != OCS_LOGIN_REQUEST_QUEUED) {
4262  ocs_cxn_close(cxn, TRUE);
4263  }
4264  }
4265 
4266  return rc;
4267 }
4268 
4269 /**
4270  * @ingroup iscsi_main
4271  * @brief Initialize the memory tracker.
4272  *
4273  * @param tracker Pointer to the tracker to initialize.
4274  */
4276 {
4277  tracker->num_objs = 0;
4278  tracker->pages = NULL;
4279  tracker->num_pages = 0;
4280  tracker->obj_per_page = 0;
4281  tracker->obj_size = 0;
4282  tracker->obj_size_padded = 0;
4283 }
4284 
4285 
4286 /**
4287  * @ingroup iscsi_main
4288  * @brief Free the memory associated with a memory tracker.
4289  *
4290  * @param iscsi Pointer to the iSCSI object.
4291  * @param tracker Pointer to the tracker.
4292  */
4294  ocs_iscsi_mem_tracker_t *tracker)
4295 {
4296  uint32_t indx;
4297 
4298  if (tracker->pages) {
4299  for (indx = 0; indx < tracker->num_pages; indx ++)
4300  {
4301  ocs_dma_free(iscsi->os, &tracker->pages[indx]);
4302  ocs_memset(&tracker->pages[indx], 0, sizeof(ocs_dma_t));
4303  }
4304  ocs_free(iscsi->os, tracker->pages,
4305  sizeof(ocs_dma_t) * (tracker->num_pages + tracker->num_objs));
4306  ocs_iscsi_tracker_init(tracker);
4307  }
4308 }
4309 
4310 
4311 /**
4312  * @ingroup iscsi_main
4313  * @brief Allocate a group of objects uses pages to minimize waste.
4314  *
4315  * @par Description
4316  * Used to allocate groups of objects into pages and then pull them
4317  * out. This is done because DMA memory is allocated on page boundaries,
4318  * which causes wasted space. By grouping the structures together, we attempt
4319  * to consolidate as many per page as possible.
4320  *
4321  * @param iscsi Pointer to the iSCSI object.
4322  * @param tracker Pointer to the tracker.
4323  * @param zero If non-zero, then the memory will be zeroed.
4324  * @param object_size The size of the objects in bytes.
4325  * @param alignment Minimum byte alignment.
4326  * @param num_objects Number of object to allocate.
4327  *
4328  * @return Returns 0 on success, or a non-zero value otherwise.
4329  */
4330 int32_t
4332  ocs_iscsi_mem_tracker_t *tracker,
4333  uint8_t zero,
4334  uint32_t object_size,
4335  uint32_t alignment,
4336  uint32_t num_objects)
4337 {
4338  uint32_t indx;
4339  uint32_t padded_size;
4340  uint32_t obj_per_page;
4341  uint32_t num_pages;
4342  uint32_t alloc_size = OCS_ISCSI_PAGE_SIZE;
4343 
4344  /* Calculated the padded object size based on the alignment */
4345  if (alignment == 0 ||
4346  (alignment < object_size &&
4347  (object_size % alignment == 0))) {
4348  padded_size = object_size;
4349  } else {
4350  padded_size = object_size + (object_size % alignment);
4351  }
4352  ocs_log_debug(iscsi->os, "alignment %d, object size %d, padded size %d\n",
4353  alignment, object_size, padded_size);
4354 
4355  obj_per_page = OCS_ISCSI_PAGE_SIZE / padded_size;
4356 
4357  /* Acoount for the case where the object is bigger than a page */
4358  if (obj_per_page == 0) {
4359  alloc_size = (((padded_size + (OCS_ISCSI_PAGE_SIZE - 1)) / OCS_ISCSI_PAGE_SIZE) *
4361  obj_per_page = 1;
4362  }
4363 
4364  num_pages = ((num_objects + (obj_per_page - 1)) / obj_per_page);
4365 
4366  tracker->pages = (ocs_dma_t *)ocs_malloc(iscsi->os, sizeof(ocs_dma_t) *
4367  (num_pages + num_objects),
4368  OCS_M_ZERO | OCS_M_NOWAIT);
4369  if (tracker->pages == NULL) {
4370  ocs_log_err(iscsi->os, "memory allocation failed for ocs_dma_t entries\n");
4371  return -ENOMEM;
4372  }
4373 
4374  for (indx = 0; indx < num_pages; indx++) {
4375  if (ocs_dma_alloc(iscsi->os,
4376  &tracker->pages[indx],
4377  alloc_size,
4378  alignment)) {
4379  uint32_t indx_free;
4380 
4381  ocs_log_err(iscsi->os,
4382  "memory allocation failed page %d\n",
4383  indx);
4384 
4385  for (indx_free = 0; indx_free < indx; indx_free++)
4386  {
4387  ocs_dma_free(iscsi->os, &tracker->pages[indx_free]);
4388  }
4389  ocs_free(iscsi->os, tracker->pages, sizeof(ocs_dma_t) * num_pages);
4390  ocs_iscsi_tracker_init(tracker);
4391  return -ENOMEM;
4392  }
4393  if (zero) {
4394  ocs_memset(tracker->pages[indx].virt, 0, alloc_size);
4395  }
4396  }
4397 
4398  /*
4399  * Calculate the DMA values for each object - Required for Rx buffers.
4400  */
4401  for (indx = 0; indx < num_objects; indx++) {
4402  uint32_t page_index = indx / obj_per_page;
4403  uint32_t mem_offset = ((indx % obj_per_page) * padded_size);
4404  ocs_dma_t *mem = &tracker->pages[num_pages + indx];
4405 
4406  mem->virt = ((uint8_t*)tracker->pages[page_index].virt) + mem_offset;
4407  mem->phys = tracker->pages[page_index].phys + mem_offset;
4408  mem->size = object_size;
4409  }
4410 
4411  tracker->num_objs = num_objects;
4412  tracker->num_pages = num_pages;
4413  tracker->obj_per_page = obj_per_page;
4414  tracker->obj_size = object_size;
4415  tracker->obj_size_padded = padded_size;
4416  return 0;
4417 }
4418 
4419 /**
4420  * @ingroup iscsi_main
4421  * @brief Helper to return the pointers for a specific object in the group.
4422  *
4423  * @param tracker Pointer to the tracker.
4424  * @param obj_offset Number of the object to retrieve.
4425  *
4426  * @return Returns the pointer on success, NULL otherwise.
4427  */
4428 ocs_dma_t *
4430  uint32_t obj_offset)
4431 {
4432  ocs_dma_t *rval = NULL;
4433  if (obj_offset < tracker->num_objs) {
4434  rval = &tracker->pages[tracker->num_pages + obj_offset];
4435  }
4436  return rval;
4437 }
4438 
4439 /**
4440  * @brief Add a receive buffer pair to the Receive Queue, if an error is received, then queue the buffer.
4441  *
4442  * @param iscsi Pointer to the iSCSI object.
4443  * @param header DMA memory for the unsolicited header.
4444  * @param payload DMA memory for the unsolicited payload.
4445  */
4446 void
4448  ocs_hal_rtn_e rc;
4449 
4450  rc = ocs_hal_rxbuffer(iscsi->hal, header, payload);
4451  if (rc != OCS_HAL_RTN_SUCCESS) {
4452  ocs_log_test(iscsi->os, "Failed post RQ buffers - buffers leaked\n");
4453  }
4454 }
4455 
4457 {
4458  ocs_hal_t *hal = iscsi->hal;
4459  ocs_sli_port_t *sport;
4460  int32_t inters;
4461 
4462  if (hal->domain == NULL) {
4463  return;
4464  }
4465 
4466  /* Return if no active connections */
4467  if (hal->domain->node_instance_count == 0) {
4468  return;
4469  }
4470 
4471  ocs_log_debug(iscsi->os, "Invalidate active connections\n");
4472  ocs_domain_lock(hal->domain);
4473  ocs_list_foreach(&hal->domain->sport_list, sport) {
4474  ocs_sport_lock(sport);
4475 
4476  ocs_hal_cxn_req_invalidate(&sport->node_list);
4477 
4478  ocs_sport_unlock(sport);
4479  }
4480  ocs_domain_unlock(hal->domain);
4481 
4482  inters = 100;
4483  do {
4484  ocs_delay_usec(10000);
4485  inters--;
4486  } while (inters);
4487  ocs_log_debug(iscsi->os, "Done waiting for connection invalidation\n");
4488 }
ocs_atomic_t in_use
Definition: ocs_iscsi.h:211
int32_t ocs_scsi_ini_new_sport(ocs_sport_t *sport)
Process creation of a new SPORT.
static ocs_config_ctx_t * ocs_iscsi_ctx_alloc(ocs_iscsi_t *iscsi, ocs_config_ctx_e index)
Allocates an iSCSI API context that provides a synchronous API when using a asynchronous mailbox comm...
Definition: ocs_iscsi.c:174
uint8_t gateway[64]
Definition: ocs_ioctl.h:291
ocs_hal_io_t * io
Definition: ocs_hal.h:615
structure for storing VLAN id and interface handle together
#define OCS_ISCSI_LOGIN_DEFAULT_TIME_2_WAIT
Stores information needed IP addresses for targets.
Definition: ocs_iscsi.h:276
static void ocs_iscsi_convert_to_ipsub(ocs_ip_address_subnet_t *ip, ocs_hal_ip_address_subnet_t *hal_ip)
Convert an iSCSI IP address to the HAL IP address.
Definition: ocs_iscsi.c:399
Defines the iSCSI command PDU header.
#define ISCSI_RESP_DATAIN
ocs_hal_ip_type_e ip_type
Definition: ocs_hal.h:268
static void ocs_sport_unlock(ocs_sport_t *sport)
Definition: ocs_common.h:136
#define ISCSI_LUN_ADDR_METHOD_EXTENDED
Definition: ocs_iscsi.h:59
int32_t ocs_iscsi_remove_ip_from_tbl(ocs_t *ocs, ocs_ip_address_subnet_t *ipsub, ocs_hal_portal_t portal)
Remove an IP address from the table.
Definition: ocs_iscsi.c:2696
uint8_t scsi_status
Definition: ocs_scsi.h:92
int32_t ocs_iscsi_send_logout(ocs_cxn_t *cxn, uint8_t immediate, uint8_t reason_code)
Function to send a logout PDU.
Definition: ocs_login.c:3992
ocs_hal_rtn_e ocs_hal_portal_gateway_add(ocs_hal_t *hal, ocs_hal_ip_address_t *gateway, portal_cb_t portal_cb, void *ul_arg)
adds the default gateway on an interface.
Definition: ocs_hal.c:4057
ocs_link_state_e
enum identifying the link state.
Definition: ocs_iscsi_api.h:66
#define ISCSI_CQE_CODE_RECV_PDU_DSL_ERROR
Definition: sli4_iscsi.h:1086
ocs_iscsi_route_table_entry_t entry[OCS_ISCSI_ROUTE_TABLE_ENTRIES_MAX]
Definition: ocs_iscsi.h:178
ocs_scsi_tmf_cmd_e
Definition: ocs_scsi.h:138
static void ocs_iscsi_ctx_general_cb(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
This function is the callback a general API context command.
Definition: ocs_iscsi.c:927
int32_t ocs_iscsi_tgt_add(ocs_t *ocs, char *name, char *alias)
Adds a target.
ocs_hal_portal_t iface
Definition: ocs_iscsi.h:223
uint32_t isns_pkt_len
Definition: ocs_iscsi.h:219
int32_t ocs_scsi_recv_tmf(ocs_io_t *tmfio, uint32_t lun, ocs_scsi_tmf_cmd_e cmd, ocs_io_t *abortio, uint32_t flags)
Receive a TMF command IO.
Definition: ocs_ramd.c:2682
int32_t ocs_scsi_tgt_del_device(ocs_t *ocs)
Tears down the target members of the ocs structure.
Definition: ocs_ramd.c:836
static void ocs_iscsi_query_ip_cb(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
This function is the callback for querying IP addresses.
Definition: ocs_iscsi.c:1253
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
int32_t ocs_iscsi_recv_login_rsp(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Function to process a login response PDU.
Definition: ocs_login.c:2893
int32_t ocs_scsi_tgt_new_device(ocs_t *ocs)
Initializes any target fields on the ocs structure.
Definition: ocs_ramd.c:753
bool shutting_down
Definition: ocs_iscsi.h:305
ocs_io_pool_t * ocs_io_pool_create(ocs_t *ocs, uint32_t num_io, uint32_t num_sgl)
Create a pool of IO objects.
Definition: ocs_io.c:90
int32_t ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len)
Definition: ocs_driver.c:357
#define ISCSI_CQE_CODE_ITT_TTT_WRONG_CXN
Definition: sli4_iscsi.h:1091
int32_t ocs_scsi_ini_new_domain(ocs_domain_t *domain)
Accept new domain notification.
ocs_pdu_process_rtn_e ocs_iscsi_recv_login(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Function to process a login PDU on a target.
Definition: ocs_login.c:2450
int32_t ocs_iscsi_send_async(ocs_cxn_t *cxn, void *payload, uint32_t payload_len, uint8_t reason, uint64_t lun, uint16_t param1, uint16_t param2, uint16_t param3)
Sends a asynchronous PDU with an optional payload.
Definition: ocs_login.c:4792
#define OCS_SCSI_CMD_HEAD_OF_QUEUE
Definition: ocs_scsi.h:50
#define ISCSI_LUN_RESET
uint32_t ExpectedDataTransferLength
ocs_pdu_process_rtn_e
iSCSI PDU processing return codes
Definition: ocs_iscsi.h:99
void ocs_domain_force_free(ocs_domain_t *domain)
Free memory resources of a domain object.
Definition: ocs_domain.c:147
ocs_config_ctx_e
The types of mailbox operations we want to wait for.
Definition: ocs_iscsi.h:186
uint16_t size
Definition: sli4.h:2051
ocs_hal_rtn_e ocs_hal_portal_isns_send_packet(ocs_hal_t *hal, ocs_hal_ip_address_t *isns_server, uint32_t tcp_port, void *packet, uint32_t pkt_len, portal_cb_t portal_cb, void *ul_arg)
Sends an iSNS packet to the requested server.
Definition: ocs_hal.c:4324
void(* ocs_link_state_cb_t)(ocs_t *, ocs_link_state_e)
Template for a function to be called when the link state changes.
Definition: ocs_iscsi.h:234
ocs_hal_t * hal
Definition: ocs_iscsi.h:295
uint8_t data_segment_length[3]
ocs_hal_rtn_e ocs_hal_init(ocs_hal_t *hal)
Set up Hardware Abstraction Layer module.
Definition: ocs_hal.c:201
int32_t ocs_iscsi_login_initialize(ocs_iscsi_t *iscsi)
Initialize the login and retry object used within the login module.
Definition: ocs_login.c:200
void ocs_iscsi_cluster_tgts_free(ocs_iscsi_t *iscsi)
iscsi cluster targets free
Definition: ocs_iscsi.c:2211
uint32_t ext_status
Definition: ocs_iscsi.h:215
int32_t parse_mac_address(const char *src, uint8_t *dest)
Parse a string into a MAC address.
Definition: ocs_iscsi.c:737
#define ISCSI_LUN_ADDRESS_METHOD_MASK
Definition: ocs_iscsi.h:55
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
static void ocs_sport_lock(ocs_sport_t *sport)
Definition: ocs_common.h:131
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
uint8_t ip_address[16]
Definition: ocs_hal.h:261
#define ISCSI_LUN_ADDRESS_METHOD_SHIFT
Definition: ocs_iscsi.h:54
ocs_hal_rtn_e ocs_hal_domain_add(ocs_hal_t *hal, ocs_sli_port_t *sport, ocs_domain_t *domain)
Adds a domain object.
Definition: ocs_hal.c:3037
int32_t ocs_iscsi_find_portal_from_vlan(ocs_t *ocs, uint32_t vlan_id, ocs_hal_portal_t *iface_handle)
Helper function to find respective interface handle of VLAN id.
Definition: ocs_iscsi.c:2921
static int32_t ocs_iscsi_link_event_cb(void *arg, uint8_t isLinkUp)
Function to receive the notification of link events.
Definition: ocs_iscsi.c:3385
#define ISCSI_RESP_TASK
#define ISCSI_CQE_CODE_RECV_UNSOL_PDU_ERROR
Definition: sli4_iscsi.h:1117
struct sli4_queue_t::@33::@35 wq
int32_t ocs_iscsi_portal_is_vlan_exists(ocs_t *ocs, uint32_t vlan_id)
Check VLAN for duplicate.
Definition: ocs_iscsi.c:2949
ocs_config_ctx_t * ctx
Definition: ocs_iscsi.h:321
ocs_hal_rtn_e ocs_hal_teardown(ocs_hal_t *hal)
Tear down Hardware Abstraction Layer module.
Definition: ocs_hal.c:2409
uint32_t num_ips
Definition: ocs_iscsi.h:224
static ocs_pdu_process_rtn_e ocs_iscsi_recv_tm(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len)
Function to receive unsolicited task management PDUs.
Definition: ocs_iscsi.c:3838
#define DRV_VERSION
Definition: ocs.h:45
uint32_t entry_count
Definition: ocs_ioctl.h:295
int32_t ocs_cxn_initialize(ocs_iscsi_t *iscsi)
Initialize the iSCSI connection objects.
Definition: ocs_cxn.c:121
ocs_lock_t api_list_lock
static void ocs_iscsi_ctx_post(ocs_config_ctx_t *ctx, int32_t status, uint32_t ext_status)
Updates the status fields and post to the semaphore if it is still in use.
Definition: ocs_iscsi.c:251
structure wrapping an IP address and subnet together with their type.
Definition: ocs_hal.h:267
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
Structure to hold the fields returned on a target data digest error event.
Definition: ocs_hal.h:608
#define OCS_CHAP_MODE_TARGET
Definition: ocs_ioctl.h:275
#define OCS_IQN_SUFFIX_DEFAULT
Definition: ocs_common.h:241
#define ISCSI_CQE_CODE_RESIDUAL_UNDERRUN
Definition: sli4_iscsi.h:1100
int32_t ocs_scsi_tgt_new_sport(ocs_sport_t *sport)
Accept a new SLI Port notification.
Definition: ocs_ramd.c:924
int loglevel
Definition: ocs_lnx.c:25
#define OCS_ISCSI_MAX_LINK_STATE_CALLBACKS
Definition: ocs_iscsi.h:236
ocs_hal_ip_type_e
enum identifying the types of IP addresses.
Definition: ocs_hal.h:244
static void ocs_iscsi_convert_to_hal_ipsub(ocs_ip_address_subnet_t *ip, ocs_hal_ip_address_subnet_t *hal_ip)
Convert an iSCSI IP address to the HAL IP address.
Definition: ocs_iscsi.c:385
ocs_hal_rtn_e ocs_hal_portal_esi_listen_stop(ocs_hal_t *hal, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, portal_cb_t portal_cb, void *ul_arg)
Stops listening on an iSNS ESI TCP port.
Definition: ocs_hal.c:4425
#define ISCSI_TASK_REASSIGN
ocs_hal_portal_t portal
Definition: ocs_iscsi.h:278
ocs_hal_rtn_e
defines common HAL return statuses.
Definition: ocs_hal.h:78
ocs_hal_rtn_e ocs_hal_portal_listen_start(ocs_hal_t *hal, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, portal_cb_t portal_cb, void *ul_arg)
Starts listening on a TCP port.
Definition: ocs_hal.c:4147
#define ISCSI_RESP_TEXT
static void ocs_iscsi_ctx_free(ocs_iscsi_t *iscsi, ocs_config_ctx_e index)
Frees an iSCSI API context that provides a synchronous API when using a asynchronous mailbox command...
Definition: ocs_iscsi.c:238
ocs_hal_rtn_e ocs_hal_portal_ip_add(ocs_hal_t *hal, ocs_hal_portal_t portal, ocs_hal_ip_address_subnet_t *ipaddr, portal_cb_t portal_cb, void *ul_arg)
Add an IP address to an interface.
Definition: ocs_hal.c:3727
Defines the iSCSI task management PDU header.
int32_t ocs_iscsi_portal_find_ip_address(ocs_t *ocs, ocs_hal_portal_t iface_handle, ocs_ip_address_t *ip, ocs_ip_address_t *subnet, uint16_t *tcp_port, int32_t *listening)
Find IP address of interface handle If IP address is found for given interface handle, copy to ip and subnet params.
Definition: ocs_iscsi.c:2830
sli4_t sli
Definition: ocs_hal.h:726
iscsi_hdr_dw2_t dw2
bool has_ue_occurred
Definition: ocs_iscsi.h:308
ocs_iscsi_cluster_tgt_t * ctgt_next
Definition: ocs_iscsi.h:268
ocs_pdu_process_rtn_e ocs_iscsi_tgt_process_cmd_sn(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code, uint8_t *reject_reason)
Function to process unsolicited PDUs for a target.
Definition: ocs_iscsi.c:4042
void format_mac_address(uint8_t *address, char *buffer, int size)
Format a MAC address into a string.
Definition: ocs_iscsi.c:711
static void ocs_iscsi_idle_timeout(void *arg)
This function is called to check for idle connections.
Definition: ocs_iscsi.c:818
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_scsi_tgt_del_domain(ocs_domain_t *domain)
Accept a domain lost notification.
Definition: ocs_ramd.c:902
static int32_t ocs_iscsi_hal_configure(ocs_iscsi_t *iscsi)
Configure the HAL based on iSCSI compile parameters.
Definition: ocs_iscsi.c:2015
#define CONN_STATE_LOGIN_PROGRESS
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
ocs_pdu_process_rtn_e ocs_iscsi_recv_text(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t *reject_reason)
Function to process a text PDU.
Definition: ocs_login.c:3546
ocs_hal_ip_address_t subnet
Definition: ocs_iscsi.h:172
ocs_domain_t * domain
Definition: ocs_hal.h:727
Structure to define what connection event occurred and it&#39;s parameters.
Definition: ocs_hal.h:637
HAL object.
Definition: ocs_hal.h:724
void ocs_iscsi_cxn_req_invalidate(ocs_iscsi_t *iscsi)
Definition: ocs_iscsi.c:4456
uint16_t icd
Definition: ocs_hal.h:474
static void ocs_iscsi_isns_send_cb(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
This function is the callback for the iSNS send.
Definition: ocs_iscsi.c:986
static int32_t ocs_iscsi_unsolicited_event_cb(void *arg, ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code)
Function to receive unsolicited PDUs.
Definition: ocs_iscsi.c:4210
void ocs_hal_cxn_req_invalidate(ocs_list_t *list_cxn)
Definition: ocs_hal.c:7547
void ocs_iscsi_login_teardown(ocs_iscsi_t *iscsi)
Releases the login and retry object used within the login module.
Definition: ocs_login.c:227
uint8_t subnet[64]
Definition: ocs_ioctl.h:290
ocs_hal_rtn_e ocs_hal_portal_set_mac(ocs_hal_t *hal, uint8_t *mac_address, portal_cb_t portal_cb, void *ul_arg)
Set the MAC address on the portal.
Definition: ocs_hal.c:3122
ocs_hal_rtn_e ocs_hal_callback(ocs_hal_t *hal, ocs_hal_callback_e which, void *func, void *arg)
register a callback for the given event.
Definition: ocs_hal.c:2203
ocs_cxn_t * cxn
Definition: ocs_hal.h:623
ocs_mgmt_functions_t sport_mgmt_functions
Definition: ocs_sport.c:47
int32_t(* ocs_scsi_rsp_io_cb_t)(ocs_io_t *io, ocs_scsi_io_status_e status, ocs_scsi_cmd_resp_t *rsp, uint32_t flags, void *arg)
Definition: ocs_scsi.h:129
#define ISCSI_RESP_NOOP
#define ISCSI_CQE_CODE_RECV_AHS_NOT_SUPPORTED
Definition: sli4_iscsi.h:1088
void ocs_scsi_io_free(ocs_io_t *io)
Free a SCSI IO context.
Definition: ocs_scsi.c:2264
#define CONN_STATE_NEW_CONN
#define OCS_SCSI_CMD_ACA
Definition: ocs_scsi.h:53
#define ISCSI_CMD_TEXT
int32_t ocs_iscsi_send_reject(ocs_cxn_t *cxn, void *hdr, uint32_t hdr_len, uint8_t reason)
Sends a reject PDU for the supplied PDU header.
Definition: ocs_login.c:4652
int32_t ocs_session_initialize(ocs_iscsi_t *iscsi)
Initialize the session management by allocating objects for sessions.
Definition: ocs_session.c:67
uint32_t ocs_hal_portal_t
Definition: ocs_common.h:204
ocs_timer_t idle_timer
Definition: ocs_iscsi.h:302
#define OCS_SCSI_CMD_DIR_OUT
Definition: ocs_scsi.h:48
#define OCS_ISCSI_MAX_ALIAS_SIZE
#define OCS_DEBUG_ALWAYS
Definition: ocs_debug.h:154
uint32_t ttt
Definition: ocs_hal.h:492
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
union ocs_hal_cxn_event_t::@18 params
union sli4_queue_t::@33 u
ocs_ip_type_e ip_type
Definition: ocs_iscsi_api.h:75
#define ISCSI_ABORT_TASK_SET
uint32_t sli_reg_read(sli4_t *sli, sli4_regname_e reg)
Read the given SLI register.
Definition: sli4.c:210
#define ISCSI_TASK_MGMT_TASK_DOES_NOT_EXIST
void ocs_iscsi_uninitialize(ocs_iscsi_t *iscsi)
Indicate that HAL is not initialized.
Definition: ocs_iscsi.c:1904
#define ISCSI_ORDERED_QUEUE_TAG
ocs_hal_rtn_e ocs_hal_portal_ip_remove(ocs_hal_t *hal, ocs_hal_portal_t portal, ocs_hal_ip_address_subnet_t *ipaddr, portal_cb_t portal_cb, void *ul_arg)
Removes an IP address from an interface.
Definition: ocs_hal.c:3802
static int32_t ocs_iscsi_cxn_event_data_digest(ocs_iscsi_t *iscsi, ocs_hal_tgt_data_digest_t *tgt_digest)
Function to process a data digest error.
Definition: ocs_iscsi.c:3555
void ocs_scsi_tgt_del_sport(ocs_sport_t *sport)
Accept a SLI Port gone notification.
Definition: ocs_ramd.c:974
#define OCS_CHAP_TYPE_INCOMING
Definition: ocs_ioctl.h:273
void ocs_cxn_teardown(ocs_iscsi_t *iscsi)
Free the iSCSI connection objects.
Definition: ocs_cxn.c:155
static ocs_pdu_process_rtn_e ocs_iscsi_recv_cmd(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Function to receive unsolicited command PDUs.
Definition: ocs_iscsi.c:3705
int32_t ocs_iscsi_route_table_read(ocs_t *ocs, ocs_route_table_t *route_table)
Definition: ocs_iscsi.c:2371
static void ocs_iscsi_ctx_teardown(ocs_iscsi_t *iscsi)
Completes any active iSCSI API context when the device is being shut down.
Definition: ocs_iscsi.c:273
ocs_lock_t lock
Definition: sli4.h:2049
uint32_t num_ios
Definition: ocs_iscsi.h:300
SCSI command response.
Definition: ocs_scsi.h:91
ocs_domain_t * ocs_domain_alloc(ocs_t *ocs)
Allocate a domain object.
Definition: ocs_domain.c:71
uint8_t * ocs_iscsi_mac_get(ocs_t *ocs)
Gets the MAC address of the iSCSI device.
Definition: ocs_iscsi.c:1323
ocs_link_state_cb_t link_state_callbacks[OCS_ISCSI_MAX_LINK_STATE_CALLBACKS]
Definition: ocs_iscsi.h:341
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
int32_t ocs_iscsi_send_nop_out(ocs_cxn_t *cxn, uint64_t lun, uint32_t itt, uint32_t ttt, char *data_ptr, uint32_t data_len)
Send NOP-Out from an initiator.
Definition: ocs_login.c:4250
uint8_t cdb[16]
static int32_t ocs_iscsi_cxn_event_cb(void *arg, ocs_hal_cxn_event_t *)
Function to receive connection events.
Definition: ocs_iscsi.c:3601
#define ISCSI_RESP_LOGIN
#define ISCSI_CLEAR_TASK_SET
void ocs_dump32(uint32_t mask, ocs_os_handle_t os, const char *label, void *buf, uint32_t buf_length)
Dump 32 bit hex/ascii data.
Definition: ocs_dump32.c:72
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.
#define ISCSI_CMD_LOGOUT
#define ISCSI_ACA_TAG
static void ocs_sport_lock_init(ocs_sport_t *sport)
Definition: ocs_common.h:116
int32_t ip_type
Definition: ocs_ioctl.h:288
ocs_ip_type_e ocs_iscsi_convert_to_ip_type(ocs_hal_ip_type_e ip_type)
Convert an HAL IP type to the iSCSI API value.
Definition: ocs_iscsi.c:327
ocs_hal_rtn_e ocs_hal_portal_delete(ocs_hal_t *hal, ocs_hal_portal_t portal, portal_cb_t portal_cb, void *ul_arg)
Delete a VLAN interface handle.
Definition: ocs_hal.c:3307
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 ISCSI_CMD_CMD
ocs_hal_portal_t ocs_iscsi_portal_get_default(ocs_t *ocs)
Retrieves the default portal.
Definition: ocs_iscsi.c:2816
int32_t ocs_hal_process(ocs_hal_t *hal, uint32_t vector, uint32_t max_isr_time_msec)
Process events associated with the interrupt vector.
Definition: ocs_hal.c:2971
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
static int32_t ocs_iscsi_cxn_request_logout(ocs_cxn_t *cxn)
Attempts to send an asynchronous message to request the initiator to logout.
Definition: ocs_iscsi.c:782
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
static int32_t ocs_iscsi_unsolicited_event_ini(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code)
Function to receive unsolicited PDUs for an initiator.
Definition: ocs_iscsi.c:4116
int32_t ocs_scsi_ini_del_device(ocs_t *ocs)
Tears down initiator members of ocs structure.
#define OCS_SCSI_CMD_UNTAGGED
Definition: ocs_scsi.h:52
#define OCS_SCSI_CMD_SIMPLE
Definition: ocs_scsi.h:49
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
Defines the iSCSI task management response PDU header.
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
int32_t ocs_session_tgt_unsol_pdu_recv(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code)
Function to handle unsolicited PDUs on a target.
Definition: ocs_session.c:699
int32_t status
Definition: ocs_iscsi.h:214
ocs_hal_ip_address_subnet_t ipsub[5]
Definition: ocs_hal.h:295
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
Definition: ocs_hal.c:2666
#define CONN_STATE_LOGOUT_REQUESTED
#define ISCSI_RESP_RESP
void ocs_iscsi_tracker_init(ocs_iscsi_mem_tracker_t *tracker)
Initialize the memory tracker.
Definition: ocs_iscsi.c:4275
ocs_hal_cxn_new_t cxn_new
Definition: ocs_hal.h:642
static void ocs_iscsi_print_module_params(ocs_iscsi_t *iscsi)
This function prints the module parameters to the log for debugging purposes.
Definition: ocs_iscsi.c:1334
ocs_hal_ip_address_t ip_addr
Definition: ocs_iscsi.h:171
#define ISCSI_CMD_NOOP
#define ASYNC_EVENT_CONN_CLOSE
iSCSI object
Definition: ocs_iscsi.h:293
ocs_pdu_process_rtn_e ocs_iscsi_recv_nop_out(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Handle NOP-OUT from an initiator.
Definition: ocs_login.c:4560
int32_t ocs_scsi_tgt_new_domain(ocs_domain_t *domain)
Accept a new domain notification.
Definition: ocs_ramd.c:880
ocs_hal_rtn_e ocs_hal_set_ptr(ocs_hal_t *hal, ocs_hal_property_e prop, void *value)
Definition: ocs_hal.c:2897
#define OCS_SCSI_CMD_ORDERED
Definition: ocs_scsi.h:51
uint32_t num_cxns
Definition: ocs_iscsi.h:299
#define io_trace(io, fmt,...)
Definition: ocs_debug.h:187
structure used to signal when a mailbox command callback is complete and passes the status and any ot...
Definition: ocs_iscsi.h:209
#define ISCSI_ABORT_TASK
ocs_hal_portal_t iface_handle
int32_t ocs_iscsi_api_initialize(ocs_t *ocs)
Initialize the higher level iSCSI software.
ocs_hal_ip_type_e ip_type
Definition: ocs_hal.h:260
Defines a wrapper for the RQ payload buffers so that we can place it back on the proper queue...
Definition: ocs_hal.h:694
HAL IO object.
Definition: ocs_hal.h:471
int32_t ocs_scsi_new_target(ocs_node_t *node)
Receive notification of a new SCSI target node.
ocs_pdu_process_rtn_e ocs_iscsi_recv_logout(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len)
Function to process a logout PDU.
Definition: ocs_login.c:3881
uint16_t wrb_index
Definition: sli4.h:2037
ocs_route_table_t route_table
Definition: ocs_iscsi.h:227
This structure is used to track the WQEs for iSCSI.
Definition: sli4.h:2034
ocs_os_handle_t os
Definition: ocs_iscsi.h:294
#define ISCSI_CQE_CODE_CMD_DATA_DIFF_CXN
Definition: sli4_iscsi.h:1115
static int32_t ocs_iscsi_ctx_wait(ocs_iscsi_t *iscsi, ocs_config_ctx_e index, int timeout_usec)
Waits on an iSCSI API context until the command completes or the timeout occurs.
Definition: ocs_iscsi.c:199
iscsi_hdr_dw2_t dw2
#define ISCSI_CQE_CODE_RESIDUAL_OVERRUN
Definition: sli4_iscsi.h:1099
#define ISCSI_SIMPLE_TAG
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
ocs_route_table_entry_t entry[OCS_ISCSI_ROUTE_TABLE_ENTRIES_MAX]
Definition: ocs_ioctl.h:296
#define ocs_is_initiator_enabled()
uint32_t listening
Definition: ocs_iscsi.h:283
uint16_t tcp_port
Definition: ocs_iscsi.h:281
static void ocs_iscsi_portal_create_cb(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
This function is the callback for creating an interface/portal.
Definition: ocs_iscsi.c:3103
uint32_t ocs_instance(void *os)
Return the instance index of an opaque ocs structure.
Definition: ocs_driver.c:160
int32_t ocs_iscsi_send_nop_in(ocs_cxn_t *cxn, uint64_t lun, uint32_t itt, uint32_t ttt, char *data_ptr, uint32_t data_len)
Send NOP-In from a target.
Definition: ocs_login.c:4404
Used for returning IP information in return from ocs_hal_portal_ip_get()
Definition: ocs_hal.h:290
#define ISCSI_REJECT_REASON_PROTOCOL_ERR
#define ISCSI_REJECT_REASON_SNACK_REJECT
int32_t ocs_scsi_recv_cmd(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags)
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
#define ISCSI_TASK_MGMT_FUNCTION_COMPLETE
int32_t ocs_iscsi_portal_del_vlan(ocs_t *ocs, ocs_hal_portal_t iface)
Delete iface handle and VLAN from portal_list.
Definition: ocs_iscsi.c:3011
int32_t ocs_iscsi_initialize(ocs_os_handle_t os, ocs_iscsi_t *iscsi, ocs_hal_t *hal, uint32_t device_instance)
Initialize the iSCSI device by setting up the chip.
Definition: ocs_iscsi.c:1505
#define ISCSI_CQE_CODE_OPCODE_ERROR
Definition: sli4_iscsi.h:1090
ocs_hal_rtn_e ocs_hal_portal_esi_listen_start(ocs_hal_t *hal, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, portal_cb_t portal_cb, void *ul_arg)
Starts listening for iSNS ESI messages on a TCP port.
Definition: ocs_hal.c:4380
int32_t ocs_iscsi_portal_delete(ocs_t *ocs, ocs_hal_portal_t portal)
Removes a previously-created portal.
Definition: ocs_iscsi.c:3183
int32_t ocs_iscsi_teardown(ocs_iscsi_t *iscsi)
Shut down the device.
Definition: ocs_iscsi.c:1921
#define ISCSI_CLEAR_ACA
int32_t ocs_iscsi_portal_read_vlan_ids(ocs_t *ocs, void *arg_out, uint32_t arg_out_length)
Read VLAN IDs to provided buffer.
Definition: ocs_iscsi.c:3041
void ocs_session_all_abort_cmdsn(ocs_iscsi_t *iscsi, uint32_t cmdsn)
Abort a specific IO based on the cmdSN of the abort request.
Definition: ocs_session.c:994
int32_t ocs_iscsi_gateway_set(ocs_t *ocs, ocs_ip_address_t *gateway)
Sets the IP gateway address.
Definition: ocs_iscsi.c:2771
ocs_hal_rtn_e ocs_hal_set(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t value)
Definition: ocs_hal.c:2790
uint8_t ip_addr[64]
Definition: ocs_ioctl.h:289
int32_t ocs_iscsi_mac_set(ocs_t *ocs, uint8_t *mac_address)
Sets the MAC address of the iSCSI device.
Definition: ocs_iscsi.c:1281
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
uint32_t pf_num
Definition: ocs_iscsi.h:303
ocs_dma_t * ocs_iscsi_tracker_calc(ocs_iscsi_mem_tracker_t *tracker, uint32_t obj_offset)
Helper to return the pointers for a specific object in the group.
Definition: ocs_iscsi.c:4429
This structure is used to track the SLI4 queues.
Definition: sli4.h:2046
structure wrapping an IP address and subnet together with their type.
Definition: ocs_iscsi_api.h:82
static void ocs_iscsi_isns_discover_cb(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
This function is the callback for the iSNS server IP addresses.
Definition: ocs_iscsi.c:946
ocs_hal_rtn_e ocs_hal_domain_free(ocs_hal_t *hal, ocs_domain_t *domain)
Free a domain object.
Definition: ocs_hal.c:3061
int32_t ocs_isns_initialize(ocs_iscsi_t *iscsi)
Initialize the iSNS module.
Definition: ocs_isns.c:58
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
structure wrapping an IP address together with it&#39;s type.
Definition: ocs_hal.h:259
ocs_iscsi_cluster_sendtargets_t clusttgt
Definition: ocs_iscsi.h:348
static void ocs_sport_lock_free(ocs_sport_t *sport)
Definition: ocs_common.h:121
uint32_t num_tgts
Definition: ocs_iscsi.h:298
static void ocs_node_lock(ocs_node_t *node)
Definition: ocs_common.h:432
#define ISCSI_CMD_DATA_OUT
#define ISCSI_RESP_LOGOUT
int32_t ocs_iscsi_portal_remove_ip_addresses(ocs_t *ocs, ocs_hal_portal_t iface_handle)
Check and remove IP addresses of the corresponding interface.
Definition: ocs_iscsi.c:2862
static void ocs_iscsi_ctx_route_table_read_cb(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
This function is the callback a add route table command.
Definition: ocs_iscsi.c:2233
static int32_t ocs_iscsi_recv_tm_cb(ocs_io_t *io, ocs_scsi_io_status_e status, uint32_t flags, void *arg)
Callback function used to free an IO for a rejected task management function.
Definition: ocs_iscsi.c:3818
void ocs_iscsi_ipsub_split(ocs_ip_address_subnet_t *ipsub, ocs_ip_address_t *ip, ocs_ip_address_t *subnet)
Splits an iSCSI IP address and subnet from the combined structure.
Definition: ocs_iscsi.c:431
#define IDLE_TIMER_MS
Definition: ocs_iscsi.c:147
ocs_hal_rtn_e ocs_hal_portal_listen_stop(ocs_hal_t *hal, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, portal_cb_t portal_cb, void *ul_arg)
Stops listening on a TCP port.
Definition: ocs_hal.c:4201
ocs_hal_unsol_cb_t unsol_ini
Definition: ocs_iscsi.h:339
#define OCS_SCSI_CMD_DIR_IN
Definition: ocs_scsi.h:47
#define ocs_is_target_enabled()
static void * ocs_list_next(ocs_list_t *list, void *item)
Get the next item on the list.
Definition: ocs_list.h:339
ocs_ip_type_e
enum identifying the types of IP addresses.
Definition: ocs_iscsi_api.h:46
bool is_hal_initialized
Definition: ocs_iscsi.h:306
#define ISCSI_RESP_REJECT
ocs_ip_address_t ip[32]
Definition: ocs_iscsi.h:225
ocs_hal_rtn_e ocs_hal_portal_isns_discover(ocs_hal_t *hal, ocs_hal_portal_t portal, portal_cb_t portal_cb, void *ul_arg)
Discovers iSNS servers via DHCP.
Definition: ocs_hal.c:4245
int32_t ocs_iscsi_recv_logout_rsp(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len)
Handle logout response from a target.
Definition: ocs_login.c:4163
static int32_t ocs_iscsi_cxn_event_invalid(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn, uint32_t code)
Function to process connection invalidation notifications.
Definition: ocs_iscsi.c:3490
#define ISCSI_HEAD_OF_QUEUE_TAG
static void ocs_node_unlock(ocs_node_t *node)
Definition: ocs_common.h:437
#define ISCSI_RESP_ASYNC
#define ISCSI_TARGET_COLD_RESET
int32_t ocs_scsi_ini_new_device(ocs_t *ocs)
Initializes any initiator fields on the ocs structure.
#define OCS_ISCSI_PAGE_SIZE
int32_t ocs_iscsi_interrupts_required(ocs_os_handle_t os, ocs_hal_t *hal)
Returns the number of interrupts needed for this adapter.
Definition: ocs_iscsi.c:1459
int32_t ocs_iscsi_isns_send(ocs_t *ocs, ocs_ip_address_t *isns_server, uint32_t tcp_port, void *buffer, uint32_t *pkt_len, uint32_t buff_len)
Sends an iSNS packet to a server to test the interface.
Definition: ocs_iscsi.c:1196
Defines the iSCSI data-out PDU header.
uint32_t device_instance
Definition: ocs_iscsi.h:297
ocs_sem_t sem
Definition: ocs_iscsi.h:212
ocs_hal_ip_type_e ocs_iscsi_convert_to_hal_ip_type(ocs_ip_type_e ip_type)
Convert an iSCSI IP type to the HAL value.
Definition: ocs_iscsi.c:296
ocs_hal_rtn_e ocs_hal_portal_get_route_table(ocs_hal_t *hal, portal_cb_t portal_cb, void *ul_arg)
Read routing table.
Definition: ocs_hal.c:3661
int32_t ocs_io_pool_free(ocs_io_pool_t *io_pool)
Free IO objects pool.
Definition: ocs_io.c:181
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
ocs_dma_t dma
Definition: ocs_hal.h:696
static void ocs_domain_lock(ocs_domain_t *domain)
Definition: ocs_common.h:186
#define ISCSI_REJECT_REASON_DATA_DIGEST_ERR
int32_t ocs_iscsi_route_table_del_entry(ocs_t *ocs, ocs_ip_address_subnet_t *ipsub, ocs_ip_address_t *gateway)
Deletes an entry from a routing table.
Definition: ocs_iscsi.c:2276
void ocs_scsi_ini_del_sport(ocs_sport_t *sport)
Process deletion of a SPORT.
#define ISCSI_LUN_ADDR_METHOD_PERIPHERAL
Definition: ocs_iscsi.h:56
ocs_hal_ip_address_t gateway
Definition: ocs_iscsi.h:173
sli4_queue_t * wq
Definition: ocs_hal.h:749
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
ocs_lock_t link_state_cb_lock
Definition: ocs_iscsi.h:340
#define OCS_DEFAULT_SGL_COUNT
Definition: ocs_hal.h:74
int32_t ocs_isns_teardown(ocs_iscsi_t *iscsi)
Shutdown the iSNS module.
Definition: ocs_isns.c:74
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
uint32_t ip_count
Definition: ocs_hal.h:294
ocs_hal_rtn_e ocs_hal_portal_set_route_table(ocs_hal_t *hal, ocs_hal_ip_address_subnet_t *hal_ipsub, ocs_hal_ip_address_t *hal_gateway, int32_t add, portal_cb_t portal_cb, void *ul_arg)
Add/Remove an entry to routing table.
Definition: ocs_hal.c:3593
int32_t ocs_iscsi_recv_nop_in(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Handle NOP-IN from a target.
Definition: ocs_login.c:4503
ocs_hal_cxn_event_e event
Definition: ocs_hal.h:638
#define OCS_MAX_SPORTS
Definition: ocs_drv_iscsi.h:57
ocs_t * ocs
Definition: ocs_io.c:70
#define OCS_MAX_IP
Definition: ocs_iscsi.h:288
#define LOGOUT_REASON_CLOSE_CONN
ocs_hal_rtn_e ocs_hal_setup(ocs_hal_t *hal, ocs_os_handle_t os, sli4_port_type_e port_type)
Set up the Hardware Abstraction Layer module.
Definition: ocs_hal.c:100
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
iscsi_lun_t lun
ocs_ip_address_t subnet
Definition: ocs_iscsi.h:280
#define ocs_assert(cond,...)
Definition: ocs_debug.h:163
#define ISCSI_UNTAGGED_TAG
#define OCS_MAX_ISCSI_NAME
Definition: ocs_common.h:240
iSCSI object memory tracker
Definition: ocs_iscsi.h:117
#define ISCSI_TASK_MGMT_NOT_SUPPORTED
#define ISCSI_CMD_LOGIN
#define CONN_STATE_FULL_FEATURE
ocs_iscsi_tgt_ip_t * ip_info
Definition: ocs_iscsi.h:332
static uint32_t ocs_iscsi_decode_lun(uint8_t *lu)
Decode a LU Number according to SAM.
Definition: ocs_iscsi.c:3644
#define ISCSI_CQE_CODE_BAD_WQE_INDEX
Definition: sli4_iscsi.h:1098
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
void ocs_session_teardown(ocs_iscsi_t *iscsi)
Releases the session objects used within the login module.
Definition: ocs_session.c:123
ocs_hal_rtn_e ocs_hal_rxbuffer(ocs_hal_t *hal, ocs_hal_rq_buffer_t *header, ocs_hal_rq_buffer_t *payload)
Add a receive buffer pair to the Receive Queue.
Definition: ocs_hal.c:2254
#define ISCSI_LUN_ADDR_METHOD_FLAT
Definition: ocs_iscsi.h:57
int32_t ocs_iscsi_portal_create(ocs_t *ocs, unsigned int vlan_id, ocs_hal_portal_t *portal)
Creates a portal for a VLAN.
Definition: ocs_iscsi.c:3125
void * ocs_hal_get_ptr(ocs_hal_t *hal, ocs_hal_property_e prop)
Definition: ocs_hal.c:2753
#define OCS_LOGIN_REQUEST_QUEUED
Definition: ocs_login.h:134
#define ISCSI_CQE_CODE_HDR_DIGEST_ERROR
Definition: sli4_iscsi.h:1089
ocs_io_t * ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role)
allocate a SCSI IO context.
Definition: ocs_scsi.c:2187
ocs_hal_cxn_invalid_t cxn_invalid
Definition: ocs_hal.h:641
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
ocs_scsi_io_status_e
Definition: ocs_scsi.h:105
#define CONN_STATE_FREE
ocs_xport_t * ocs_xport_alloc(ocs_t *ocs)
allocate a transport object
Definition: ocs_xport.c:60
int32_t ocs_scsi_recv_cmd_first_burst(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags, ocs_dma_t first_burst_buffers[], uint32_t first_burst_bytes)
Receive an FCP SCSI command with the first burst data.
Definition: ocs_ramd.c:1230
ocs_ip_address_subnet_t ipsub[32]
Definition: ocs_iscsi.h:226
struct ocs_iscsi_s * iscsi
Definition: ocs_iscsi.h:210
structure wrapping an IP address together with it&#39;s type.
Definition: ocs_iscsi_api.h:74
#define ISCSI_RESP_R2T
uint64_t lun_64
int32_t ocs_iscsi_portal_add_vlan(ocs_t *ocs, ocs_hal_portal_t iface, uint32_t vlan_id)
Add VLAN and iface handle to portal_list.
Definition: ocs_iscsi.c:2976
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
uint8_t lun_8[8]
#define OCS_ISCSI_LOGIN_DEFAULT_TIME_2_RETAIN
uint32_t isns_buff_len
Definition: ocs_iscsi.h:220
#define ISCSI_CMD_TASK
int32_t ocs_cxn_new_tgt_connection(ocs_iscsi_t *iscsi, uint32_t conn_hdl)
Function to receive new TCP connections.
Definition: ocs_cxn.c:1564
int32_t ocs_iscsi_tracker_alloc(ocs_iscsi_t *iscsi, ocs_iscsi_mem_tracker_t *tracker, uint8_t zero, uint32_t object_size, uint32_t alignment, uint32_t num_objects)
Allocate a group of objects uses pages to minimize waste.
Definition: ocs_iscsi.c:4331
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
int32_t ocs_session_abort_itt(ocs_session_t *session, uint32_t itt)
Abort a specific IO based on the ITT.
Definition: ocs_session.c:932
void ocs_iscsi_convert_to_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:372
bool is_init_complete
Definition: ocs_iscsi.h:307
#define OCS_CHAP_TYPE_OUTGOING
Definition: ocs_ioctl.h:274
uint32_t cid
Definition: ocs_hal.h:631
int32_t ocs_iscsi_send_tmf_resp(ocs_io_t *io, uint8_t response, ocs_scsi_io_cb_t cb, void *arg)
send TMF response data
Definition: ocs_scsi.c:1320
int32_t ocs_iscsi_route_table_add_entry(ocs_t *ocs, ocs_ip_address_subnet_t *ipsub, ocs_ip_address_t *gateway)
Adds an entry to a routing table.
Definition: ocs_iscsi.c:2328
ocs_hal_tgt_data_digest_t tgt_digest
Definition: ocs_hal.h:640
void ocs_scsi_ini_del_domain(ocs_domain_t *domain)
Accept domain lost notification.
ocs_hal_rtn_e ocs_hal_portal_create(ocs_hal_t *hal, unsigned int vlan_tag, portal_cb_t portal_cb, void *ul_arg)
Create a new VLAN interface handle.
Definition: ocs_hal.c:3263
ocs_hal_rtn_e ocs_hal_portal_set_mtu(ocs_hal_t *hal, uint8_t is_jumbo, portal_cb_t portal_cb, void *ul_arg)
Enable Jumbo frame support on the portal.
Definition: ocs_hal.c:3171
static void ocs_domain_unlock(ocs_domain_t *domain)
Definition: ocs_common.h:191
sli4_port_type_e
Definition: sli4.h:2156
#define ISCSI_CQE_CODE_RECV_SEQ_BURST_ERROR
Definition: sli4_iscsi.h:1087
#define CONN_STATE_CLEANUP
#define ISCSI_CQE_CODE_ITT_TTT_TOO_BIG
Definition: sli4_iscsi.h:1092
void ocs_iscsi_tracker_free(ocs_iscsi_t *iscsi, ocs_iscsi_mem_tracker_t *tracker)
Free the memory associated with a memory tracker.
Definition: ocs_iscsi.c:4293
void ocs_session_abort_cmdsn(ocs_session_t *session, uint32_t cmdsn)
Abort a specific IO based on the cmdSN of the abort request.
Definition: ocs_session.c:965
#define ISCSI_TARGET_WARM_RESET
uint32_t num_ips
Definition: ocs_iscsi.h:331
ocs_dma_t dma
Definition: sli4.h:2048
ocs_hal_rtn_e ocs_hal_portal_ip_get(ocs_hal_t *hal, ocs_hal_portal_t portal, ocs_hal_ip_type_e ip_type, portal_cb_t portal_cb, void *ul_arg)
Retrieves the IP addresses on an interface.
Definition: ocs_hal.c:3925
static int32_t ocs_iscsi_recv_tm_rsp(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len)
Function to receive unsolicited task management response PDUs.
Definition: ocs_iscsi.c:3956
ocs_hal_portal_t ocs_hal_portal_get_default(ocs_hal_t *hal)
Return the default portal.
Definition: ocs_hal.c:3215
Defines the iSCSI login PDU header.
int32_t ocs_iscsi_api_shutdown(ocs_t *ocs)
Initialize the higher level iSCSI software.
#define ISCSI_CMD_SNACK