Print this page
3866 panic in idm module
3867 stmfCreateLu failed: GUID_IN_USE
3868 iscsi target not accepting any new connections
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Reviewed by: Jeremy Jones <jeremy@delphix.com>
Reviewed by: Eric Diven <eric.diven@delphix.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: T Nguyen <truongqnguien@gmail.com>
Approved by: Gordon Ross <gwr@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/idm/idm_so.c
+++ new/usr/src/uts/common/io/idm/idm_so.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 #include <sys/conf.h>
27 27 #include <sys/stat.h>
28 28 #include <sys/file.h>
29 29 #include <sys/ddi.h>
30 30 #include <sys/sunddi.h>
31 31 #include <sys/modctl.h>
32 32 #include <sys/priv.h>
33 33 #include <sys/cpuvar.h>
34 34 #include <sys/socket.h>
35 35 #include <sys/strsubr.h>
36 36 #include <sys/sysmacros.h>
37 37 #include <sys/sdt.h>
38 38 #include <netinet/tcp.h>
39 39 #include <inet/tcp.h>
40 40 #include <sys/socketvar.h>
41 41 #include <sys/pathname.h>
42 42 #include <sys/fs/snode.h>
43 43 #include <sys/fs/dv_node.h>
44 44 #include <sys/vnode.h>
45 45 #include <netinet/in.h>
46 46 #include <net/if.h>
47 47 #include <sys/sockio.h>
48 48 #include <sys/ksocket.h>
49 49 #include <sys/filio.h> /* FIONBIO */
50 50 #include <sys/iscsi_protocol.h>
51 51 #include <sys/idm/idm.h>
52 52 #include <sys/idm/idm_so.h>
53 53 #include <sys/idm/idm_text.h>
54 54
55 55 #define IN_PROGRESS_DELAY 1
56 56
57 57 /*
58 58 * in6addr_any is currently all zeroes, but use the macro in case this
59 59 * ever changes.
60 60 */
61 61 static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
62 62
63 63 static void idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
64 64 static void idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
65 65 static void idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
66 66
67 67 static idm_status_t idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so);
68 68 static void idm_so_conn_destroy_common(idm_conn_t *ic);
69 69 static void idm_so_conn_connect_common(idm_conn_t *ic);
70 70
71 71 static void idm_set_ini_preconnect_options(idm_so_conn_t *sc,
72 72 boolean_t boot_conn);
73 73 static void idm_set_ini_postconnect_options(idm_so_conn_t *sc);
74 74 static void idm_set_tgt_connect_options(ksocket_t so);
75 75 static idm_status_t idm_i_so_tx(idm_pdu_t *pdu);
76 76
77 77 static idm_status_t idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu);
78 78 static void idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt,
79 79 idm_buf_t *idb, uint32_t offset, uint32_t length);
80 80 static void idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb);
81 81 static idm_status_t idm_so_send_buf_region(idm_task_t *idt,
82 82 idm_buf_t *idb, uint32_t buf_region_offset, uint32_t buf_region_length);
83 83
84 84 static uint32_t idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb,
85 85 uint32_t ro, uint32_t dlength);
86 86
87 87 static idm_status_t idm_so_handle_digest(idm_conn_t *it,
88 88 nvpair_t *digest_choice, const idm_kv_xlate_t *ikvx);
89 89
90 90 static void idm_so_socket_set_nonblock(struct sonode *node);
91 91 static void idm_so_socket_set_block(struct sonode *node);
92 92
93 93 /*
94 94 * Transport ops prototypes
95 95 */
96 96 static void idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu);
97 97 static idm_status_t idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb);
98 98 static idm_status_t idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb);
99 99 static void idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu);
100 100 static void idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu);
101 101 static void idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu);
102 102 static idm_status_t idm_so_free_task_rsrc(idm_task_t *idt);
103 103 static kv_status_t idm_so_negotiate_key_values(idm_conn_t *it,
104 104 nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
105 105 static void idm_so_notice_key_values(idm_conn_t *it,
106 106 nvlist_t *negotiated_nvl);
107 107 static kv_status_t idm_so_declare_key_values(idm_conn_t *it,
108 108 nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
109 109 static boolean_t idm_so_conn_is_capable(idm_conn_req_t *ic,
110 110 idm_transport_caps_t *caps);
111 111 static idm_status_t idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen);
112 112 static void idm_so_buf_free(idm_buf_t *idb);
113 113 static idm_status_t idm_so_buf_setup(idm_buf_t *idb);
114 114 static void idm_so_buf_teardown(idm_buf_t *idb);
115 115 static idm_status_t idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is);
116 116 static void idm_so_tgt_svc_destroy(idm_svc_t *is);
117 117 static idm_status_t idm_so_tgt_svc_online(idm_svc_t *is);
118 118 static void idm_so_tgt_svc_offline(idm_svc_t *is);
119 119 static void idm_so_tgt_conn_destroy(idm_conn_t *ic);
120 120 static idm_status_t idm_so_tgt_conn_connect(idm_conn_t *ic);
121 121 static void idm_so_conn_disconnect(idm_conn_t *ic);
122 122 static idm_status_t idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic);
123 123 static void idm_so_ini_conn_destroy(idm_conn_t *ic);
124 124 static idm_status_t idm_so_ini_conn_connect(idm_conn_t *ic);
125 125
126 126 /*
127 127 * IDM Native Sockets transport operations
128 128 */
129 129 static
130 130 idm_transport_ops_t idm_so_transport_ops = {
131 131 idm_so_tx, /* it_tx_pdu */
132 132 idm_so_buf_tx_to_ini, /* it_buf_tx_to_ini */
133 133 idm_so_buf_rx_from_ini, /* it_buf_rx_from_ini */
134 134 idm_so_rx_datain, /* it_rx_datain */
135 135 idm_so_rx_rtt, /* it_rx_rtt */
136 136 idm_so_rx_dataout, /* it_rx_dataout */
137 137 NULL, /* it_alloc_conn_rsrc */
138 138 NULL, /* it_free_conn_rsrc */
139 139 NULL, /* it_tgt_enable_datamover */
140 140 NULL, /* it_ini_enable_datamover */
141 141 NULL, /* it_conn_terminate */
142 142 idm_so_free_task_rsrc, /* it_free_task_rsrc */
143 143 idm_so_negotiate_key_values, /* it_negotiate_key_values */
144 144 idm_so_notice_key_values, /* it_notice_key_values */
145 145 idm_so_conn_is_capable, /* it_conn_is_capable */
146 146 idm_so_buf_alloc, /* it_buf_alloc */
147 147 idm_so_buf_free, /* it_buf_free */
148 148 idm_so_buf_setup, /* it_buf_setup */
149 149 idm_so_buf_teardown, /* it_buf_teardown */
150 150 idm_so_tgt_svc_create, /* it_tgt_svc_create */
151 151 idm_so_tgt_svc_destroy, /* it_tgt_svc_destroy */
152 152 idm_so_tgt_svc_online, /* it_tgt_svc_online */
153 153 idm_so_tgt_svc_offline, /* it_tgt_svc_offline */
154 154 idm_so_tgt_conn_destroy, /* it_tgt_conn_destroy */
155 155 idm_so_tgt_conn_connect, /* it_tgt_conn_connect */
156 156 idm_so_conn_disconnect, /* it_tgt_conn_disconnect */
157 157 idm_so_ini_conn_create, /* it_ini_conn_create */
158 158 idm_so_ini_conn_destroy, /* it_ini_conn_destroy */
159 159 idm_so_ini_conn_connect, /* it_ini_conn_connect */
160 160 idm_so_conn_disconnect, /* it_ini_conn_disconnect */
161 161 idm_so_declare_key_values /* it_declare_key_values */
162 162 };
163 163
164 164 kmutex_t idm_so_timed_socket_mutex;
165 165 /*
166 166 * idm_so_init()
167 167 * Sockets transport initialization
168 168 */
169 169 void
170 170 idm_so_init(idm_transport_t *it)
171 171 {
172 172 /* Cache for IDM Data and R2T Transmit PDU's */
173 173 idm.idm_sotx_pdu_cache = kmem_cache_create("idm_tx_pdu_cache",
174 174 sizeof (idm_pdu_t) + sizeof (iscsi_hdr_t), 8,
175 175 &idm_sotx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP);
176 176
177 177 /* Cache for IDM Receive PDU's */
178 178 idm.idm_sorx_pdu_cache = kmem_cache_create("idm_rx_pdu_cache",
179 179 sizeof (idm_pdu_t) + IDM_SORX_CACHE_HDRLEN, 8,
180 180 &idm_sorx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP);
181 181
182 182 /* 128k buffer cache */
183 183 idm.idm_so_128k_buf_cache = kmem_cache_create("idm_128k_buf_cache",
184 184 IDM_SO_BUF_CACHE_UB, 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP);
185 185
186 186 /* Set the sockets transport ops */
187 187 it->it_ops = &idm_so_transport_ops;
188 188
189 189 mutex_init(&idm_so_timed_socket_mutex, NULL, MUTEX_DEFAULT, NULL);
190 190
191 191 }
192 192
193 193 /*
194 194 * idm_so_fini()
195 195 * Sockets transport teardown
196 196 */
197 197 void
198 198 idm_so_fini(void)
199 199 {
200 200 kmem_cache_destroy(idm.idm_so_128k_buf_cache);
201 201 kmem_cache_destroy(idm.idm_sotx_pdu_cache);
202 202 kmem_cache_destroy(idm.idm_sorx_pdu_cache);
203 203 mutex_destroy(&idm_so_timed_socket_mutex);
204 204 }
205 205
206 206 ksocket_t
207 207 idm_socreate(int domain, int type, int protocol)
208 208 {
209 209 ksocket_t ks;
210 210
211 211 if (!ksocket_socket(&ks, domain, type, protocol, KSOCKET_NOSLEEP,
212 212 CRED())) {
213 213 return (ks);
214 214 } else {
215 215 return (NULL);
216 216 }
217 217 }
218 218
219 219 /*
220 220 * idm_soshutdown will disconnect the socket and prevent subsequent PDU
221 221 * reception and transmission. The sonode still exists but its state
222 222 * gets modified to indicate it is no longer connected. Calls to
223 223 * idm_sorecv/idm_iov_sorecv will return so idm_soshutdown can be used
224 224 * regain control of a thread stuck in idm_sorecv.
225 225 */
226 226 void
227 227 idm_soshutdown(ksocket_t so)
228 228 {
229 229 (void) ksocket_shutdown(so, SHUT_RDWR, CRED());
230 230 }
231 231
232 232 /*
233 233 * idm_sodestroy releases all resources associated with a socket previously
234 234 * created with idm_socreate. The socket must be shutdown using
235 235 * idm_soshutdown before the socket is destroyed with idm_sodestroy,
236 236 * otherwise undefined behavior will result.
237 237 */
238 238 void
239 239 idm_sodestroy(ksocket_t ks)
240 240 {
241 241 (void) ksocket_close(ks, CRED());
242 242 }
243 243
244 244 /*
245 245 * Function to compare two addresses in sockaddr_storage format
246 246 */
247 247
248 248 int
249 249 idm_ss_compare(const struct sockaddr_storage *cmp_ss1,
250 250 const struct sockaddr_storage *cmp_ss2,
251 251 boolean_t v4_mapped_as_v4,
252 252 boolean_t compare_ports)
253 253 {
254 254 struct sockaddr_storage mapped_v4_ss1, mapped_v4_ss2;
255 255 const struct sockaddr_storage *ss1, *ss2;
256 256 struct in_addr *in1, *in2;
257 257 struct in6_addr *in61, *in62;
258 258 int i;
259 259
260 260 /*
261 261 * Normalize V4-mapped IPv6 addresses into V4 format if
262 262 * v4_mapped_as_v4 is B_TRUE.
263 263 */
264 264 ss1 = cmp_ss1;
265 265 ss2 = cmp_ss2;
266 266 if (v4_mapped_as_v4 && (ss1->ss_family == AF_INET6)) {
267 267 in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
268 268 if (IN6_IS_ADDR_V4MAPPED(in61)) {
269 269 bzero(&mapped_v4_ss1, sizeof (mapped_v4_ss1));
270 270 mapped_v4_ss1.ss_family = AF_INET;
271 271 ((struct sockaddr_in *)&mapped_v4_ss1)->sin_port =
272 272 ((struct sockaddr_in *)ss1)->sin_port;
273 273 IN6_V4MAPPED_TO_INADDR(in61,
274 274 &((struct sockaddr_in *)&mapped_v4_ss1)->sin_addr);
275 275 ss1 = &mapped_v4_ss1;
276 276 }
277 277 }
278 278 ss2 = cmp_ss2;
279 279 if (v4_mapped_as_v4 && (ss2->ss_family == AF_INET6)) {
280 280 in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
281 281 if (IN6_IS_ADDR_V4MAPPED(in62)) {
282 282 bzero(&mapped_v4_ss2, sizeof (mapped_v4_ss2));
283 283 mapped_v4_ss2.ss_family = AF_INET;
284 284 ((struct sockaddr_in *)&mapped_v4_ss2)->sin_port =
285 285 ((struct sockaddr_in *)ss2)->sin_port;
286 286 IN6_V4MAPPED_TO_INADDR(in62,
287 287 &((struct sockaddr_in *)&mapped_v4_ss2)->sin_addr);
288 288 ss2 = &mapped_v4_ss2;
289 289 }
290 290 }
291 291
292 292 /*
293 293 * Compare ports, then address family, then ip address
294 294 */
295 295 if (compare_ports &&
296 296 (((struct sockaddr_in *)ss1)->sin_port !=
297 297 ((struct sockaddr_in *)ss2)->sin_port)) {
298 298 if (((struct sockaddr_in *)ss1)->sin_port >
299 299 ((struct sockaddr_in *)ss2)->sin_port)
300 300 return (1);
301 301 else
302 302 return (-1);
303 303 }
304 304
305 305 /*
306 306 * ports are the same
307 307 */
308 308 if (ss1->ss_family != ss2->ss_family) {
309 309 if (ss1->ss_family == AF_INET)
310 310 return (1);
311 311 else
312 312 return (-1);
313 313 }
314 314
315 315 /*
316 316 * address families are the same
317 317 */
318 318 if (ss1->ss_family == AF_INET) {
319 319 in1 = &((struct sockaddr_in *)ss1)->sin_addr;
320 320 in2 = &((struct sockaddr_in *)ss2)->sin_addr;
321 321
322 322 if (in1->s_addr > in2->s_addr)
323 323 return (1);
324 324 else if (in1->s_addr < in2->s_addr)
325 325 return (-1);
326 326 else
327 327 return (0);
328 328 } else if (ss1->ss_family == AF_INET6) {
329 329 in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
330 330 in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
331 331
332 332 for (i = 0; i < 4; i++) {
333 333 if (in61->s6_addr32[i] > in62->s6_addr32[i])
334 334 return (1);
335 335 else if (in61->s6_addr32[i] < in62->s6_addr32[i])
336 336 return (-1);
337 337 }
338 338 return (0);
339 339 }
340 340
341 341 return (1);
342 342 }
343 343
344 344 /*
345 345 * IP address filter functions to flag addresses that should not
346 346 * go out to initiators through discovery.
347 347 */
348 348 static boolean_t
349 349 idm_v4_addr_okay(struct in_addr *in_addr)
350 350 {
351 351 in_addr_t addr = ntohl(in_addr->s_addr);
352 352
353 353 if ((INADDR_NONE == addr) ||
354 354 (IN_MULTICAST(addr)) ||
355 355 ((addr >> IN_CLASSA_NSHIFT) == 0) ||
356 356 ((addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) {
357 357 return (B_FALSE);
358 358 }
359 359 return (B_TRUE);
360 360 }
361 361
362 362 static boolean_t
363 363 idm_v6_addr_okay(struct in6_addr *addr6)
364 364 {
365 365
366 366 if ((IN6_IS_ADDR_UNSPECIFIED(addr6)) ||
367 367 (IN6_IS_ADDR_LOOPBACK(addr6)) ||
368 368 (IN6_IS_ADDR_MULTICAST(addr6)) ||
369 369 (IN6_IS_ADDR_V4MAPPED(addr6)) ||
370 370 (IN6_IS_ADDR_V4COMPAT(addr6)) ||
371 371 (IN6_IS_ADDR_LINKLOCAL(addr6))) {
372 372 return (B_FALSE);
373 373 }
374 374 return (B_TRUE);
375 375 }
376 376
377 377 /*
378 378 * idm_get_ipaddr will retrieve a list of IP Addresses which the host is
379 379 * configured with by sending down a sequence of kernel ioctl to IP STREAMS.
380 380 */
381 381 int
382 382 idm_get_ipaddr(idm_addr_list_t **ipaddr_p)
383 383 {
384 384 ksocket_t so4, so6;
385 385 struct lifnum lifn;
386 386 struct lifconf lifc;
387 387 struct lifreq *lp;
388 388 int rval;
389 389 int numifs;
390 390 int bufsize;
391 391 void *buf;
392 392 int i, j, n, rc;
393 393 struct sockaddr_storage ss;
394 394 struct sockaddr_in *sin;
395 395 struct sockaddr_in6 *sin6;
396 396 idm_addr_t *ip;
397 397 idm_addr_list_t *ipaddr = NULL;
398 398 int size_ipaddr;
399 399
400 400 *ipaddr_p = NULL;
401 401 size_ipaddr = 0;
402 402 buf = NULL;
403 403
404 404 /* create an ipv4 and ipv6 UDP socket */
405 405 if ((so6 = idm_socreate(PF_INET6, SOCK_DGRAM, 0)) == NULL)
406 406 return (0);
407 407 if ((so4 = idm_socreate(PF_INET, SOCK_DGRAM, 0)) == NULL) {
408 408 idm_sodestroy(so6);
409 409 return (0);
410 410 }
411 411
412 412
413 413 retry_count:
414 414 /* snapshot the current number of interfaces */
415 415 lifn.lifn_family = PF_UNSPEC;
416 416 lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
417 417 lifn.lifn_count = 0;
418 418 /* use vp6 for ioctls with unspecified families by default */
419 419 if (ksocket_ioctl(so6, SIOCGLIFNUM, (intptr_t)&lifn, &rval, CRED())
420 420 != 0) {
421 421 goto cleanup;
422 422 }
423 423
424 424 numifs = lifn.lifn_count;
425 425 if (numifs <= 0) {
426 426 goto cleanup;
427 427 }
428 428
429 429 /* allocate extra room in case more interfaces appear */
430 430 numifs += 10;
431 431
432 432 /* get the interface names and ip addresses */
433 433 bufsize = numifs * sizeof (struct lifreq);
434 434 buf = kmem_alloc(bufsize, KM_SLEEP);
435 435
436 436 lifc.lifc_family = AF_UNSPEC;
437 437 lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
438 438 lifc.lifc_len = bufsize;
439 439 lifc.lifc_buf = buf;
440 440 rc = ksocket_ioctl(so6, SIOCGLIFCONF, (intptr_t)&lifc, &rval, CRED());
441 441 if (rc != 0) {
442 442 goto cleanup;
443 443 }
444 444 /* if our extra room is used up, try again */
445 445 if (bufsize <= lifc.lifc_len) {
446 446 kmem_free(buf, bufsize);
447 447 buf = NULL;
448 448 goto retry_count;
449 449 }
450 450 /* calc actual number of ifconfs */
451 451 n = lifc.lifc_len / sizeof (struct lifreq);
452 452
453 453 /* get ip address */
454 454 if (n > 0) {
455 455 size_ipaddr = sizeof (idm_addr_list_t) +
456 456 (n - 1) * sizeof (idm_addr_t);
457 457 ipaddr = kmem_zalloc(size_ipaddr, KM_SLEEP);
458 458 } else {
459 459 goto cleanup;
460 460 }
461 461
462 462 /*
463 463 * Examine the array of interfaces and filter uninteresting ones
464 464 */
465 465 for (i = 0, j = 0, lp = lifc.lifc_req; i < n; i++, lp++) {
466 466
467 467 /*
468 468 * Copy the address as the SIOCGLIFFLAGS ioctl is destructive
469 469 */
470 470 ss = lp->lifr_addr;
471 471 /*
472 472 * fetch the flags using the socket of the correct family
473 473 */
474 474 switch (ss.ss_family) {
475 475 case AF_INET:
476 476 rc = ksocket_ioctl(so4, SIOCGLIFFLAGS, (intptr_t)lp,
477 477 &rval, CRED());
478 478 break;
479 479 case AF_INET6:
480 480 rc = ksocket_ioctl(so6, SIOCGLIFFLAGS, (intptr_t)lp,
481 481 &rval, CRED());
482 482 break;
483 483 default:
484 484 continue;
485 485 }
486 486 if (rc == 0) {
487 487 /*
488 488 * If we got the flags, skip uninteresting
489 489 * interfaces based on flags
490 490 */
491 491 if ((lp->lifr_flags & IFF_UP) != IFF_UP)
492 492 continue;
493 493 if (lp->lifr_flags &
494 494 (IFF_ANYCAST|IFF_NOLOCAL|IFF_DEPRECATED))
495 495 continue;
496 496 }
497 497
498 498 /* save ip address */
499 499 ip = &ipaddr->al_addrs[j];
500 500 switch (ss.ss_family) {
501 501 case AF_INET:
502 502 sin = (struct sockaddr_in *)&ss;
503 503 if (!idm_v4_addr_okay(&sin->sin_addr))
504 504 continue;
505 505 ip->a_addr.i_addr.in4 = sin->sin_addr;
506 506 ip->a_addr.i_insize = sizeof (struct in_addr);
507 507 break;
508 508 case AF_INET6:
509 509 sin6 = (struct sockaddr_in6 *)&ss;
510 510 if (!idm_v6_addr_okay(&sin6->sin6_addr))
511 511 continue;
512 512 ip->a_addr.i_addr.in6 = sin6->sin6_addr;
513 513 ip->a_addr.i_insize = sizeof (struct in6_addr);
514 514 break;
515 515 default:
516 516 continue;
517 517 }
518 518 j++;
519 519 }
520 520
521 521 if (j == 0) {
522 522 /* no valid ifaddr */
523 523 kmem_free(ipaddr, size_ipaddr);
524 524 size_ipaddr = 0;
525 525 ipaddr = NULL;
526 526 } else {
527 527 ipaddr->al_out_cnt = j;
528 528 }
529 529
530 530
531 531 cleanup:
532 532 idm_sodestroy(so6);
533 533 idm_sodestroy(so4);
534 534
535 535 if (buf != NULL)
536 536 kmem_free(buf, bufsize);
537 537
538 538 *ipaddr_p = ipaddr;
539 539 return (size_ipaddr);
540 540 }
541 541
542 542 int
543 543 idm_sorecv(ksocket_t so, void *msg, size_t len)
544 544 {
545 545 iovec_t iov;
546 546
547 547 ASSERT(so != NULL);
548 548 ASSERT(len != 0);
549 549
550 550 /*
551 551 * Fill in iovec and receive data
552 552 */
553 553 iov.iov_base = msg;
554 554 iov.iov_len = len;
555 555
556 556 return (idm_iov_sorecv(so, &iov, 1, len));
557 557 }
558 558
559 559 /*
560 560 * idm_sosendto - Sends a buffered data on a non-connected socket.
561 561 *
562 562 * This function puts the data provided on the wire by calling sosendmsg.
563 563 * It will return only when all the data has been sent or if an error
564 564 * occurs.
565 565 *
566 566 * Returns 0 for success, the socket errno value if sosendmsg fails, and
567 567 * -1 if sosendmsg returns success but uio_resid != 0
568 568 */
569 569 int
570 570 idm_sosendto(ksocket_t so, void *buff, size_t len,
571 571 struct sockaddr *name, socklen_t namelen)
572 572 {
573 573 struct msghdr msg;
574 574 struct iovec iov[1];
575 575 int error;
576 576 size_t sent = 0;
577 577
578 578 iov[0].iov_base = buff;
579 579 iov[0].iov_len = len;
580 580
581 581 /* Initialization of the message header. */
582 582 bzero(&msg, sizeof (msg));
583 583 msg.msg_iov = iov;
584 584 msg.msg_iovlen = 1;
585 585 msg.msg_name = name;
586 586 msg.msg_namelen = namelen;
587 587
588 588 if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED())) == 0) {
589 589 /* Data sent */
590 590 if (sent == len) {
591 591 /* All data sent. Success. */
592 592 return (0);
593 593 } else {
594 594 /* Not all data was sent. Failure */
595 595 return (-1);
596 596 }
597 597 }
598 598
599 599 /* Send failed */
600 600 return (error);
601 601 }
602 602
603 603 /*
604 604 * idm_iov_sosend - Sends an iovec on a connection.
605 605 *
606 606 * This function puts the data provided on the wire by calling sosendmsg.
607 607 * It will return only when all the data has been sent or if an error
608 608 * occurs.
609 609 *
610 610 * Returns 0 for success, the socket errno value if sosendmsg fails, and
611 611 * -1 if sosendmsg returns success but uio_resid != 0
612 612 */
613 613 int
614 614 idm_iov_sosend(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len)
615 615 {
616 616 struct msghdr msg;
617 617 int error;
618 618 size_t sent = 0;
619 619
620 620 ASSERT(iop != NULL);
621 621
622 622 /* Initialization of the message header. */
623 623 bzero(&msg, sizeof (msg));
624 624 msg.msg_iov = iop;
625 625 msg.msg_iovlen = iovlen;
626 626
627 627 if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED()))
628 628 == 0) {
629 629 /* Data sent */
630 630 if (sent == total_len) {
631 631 /* All data sent. Success. */
632 632 return (0);
633 633 } else {
634 634 /* Not all data was sent. Failure */
635 635 return (-1);
636 636 }
637 637 }
638 638
639 639 /* Send failed */
640 640 return (error);
641 641 }
642 642
643 643 /*
644 644 * idm_iov_sorecv - Receives an iovec from a connection
645 645 *
646 646 * This function gets the data asked for from the socket. It will return
647 647 * only when all the requested data has been retrieved or if an error
648 648 * occurs.
649 649 *
650 650 * Returns 0 for success, the socket errno value if sorecvmsg fails, and
651 651 * -1 if sorecvmsg returns success but uio_resid != 0
652 652 */
653 653 int
654 654 idm_iov_sorecv(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len)
655 655 {
656 656 struct msghdr msg;
657 657 int error;
658 658 size_t recv;
659 659 int flags;
660 660
661 661 ASSERT(iop != NULL);
662 662
663 663 /* Initialization of the message header. */
664 664 bzero(&msg, sizeof (msg));
665 665 msg.msg_iov = iop;
666 666 msg.msg_iovlen = iovlen;
667 667 flags = MSG_WAITALL;
668 668
669 669 if ((error = ksocket_recvmsg(so, &msg, flags, &recv, CRED()))
670 670 == 0) {
671 671 /* Received data */
672 672 if (recv == total_len) {
673 673 /* All requested data received. Success */
674 674 return (0);
675 675 } else {
676 676 /*
677 677 * Not all data was received. The connection has
678 678 * probably failed.
679 679 */
680 680 return (-1);
681 681 }
682 682 }
683 683
684 684 /* Receive failed */
685 685 return (error);
686 686 }
687 687
688 688 static void
689 689 idm_set_ini_preconnect_options(idm_so_conn_t *sc, boolean_t boot_conn)
690 690 {
691 691 int conn_abort = 10000;
692 692 int conn_notify = 2000;
693 693 int abort = 30000;
694 694
695 695 /* Pre-connect socket options */
696 696 (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
697 697 TCP_CONN_NOTIFY_THRESHOLD, (char *)&conn_notify, sizeof (int),
698 698 CRED());
699 699 if (boot_conn == B_FALSE) {
700 700 (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
701 701 TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int),
702 702 CRED());
703 703 (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
704 704 TCP_ABORT_THRESHOLD,
705 705 (char *)&abort, sizeof (int), CRED());
706 706 }
707 707 }
708 708
709 709 static void
710 710 idm_set_ini_postconnect_options(idm_so_conn_t *sc)
711 711 {
712 712 int32_t rcvbuf = IDM_RCVBUF_SIZE;
713 713 int32_t sndbuf = IDM_SNDBUF_SIZE;
714 714 const int on = 1;
715 715
716 716 /* Set postconnect options */
717 717 (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, TCP_NODELAY,
718 718 (char *)&on, sizeof (int), CRED());
719 719 (void) ksocket_setsockopt(sc->ic_so, SOL_SOCKET, SO_RCVBUF,
720 720 (char *)&rcvbuf, sizeof (int), CRED());
721 721 (void) ksocket_setsockopt(sc->ic_so, SOL_SOCKET, SO_SNDBUF,
722 722 (char *)&sndbuf, sizeof (int), CRED());
723 723 }
724 724
725 725 static void
726 726 idm_set_tgt_connect_options(ksocket_t ks)
727 727 {
728 728 int32_t rcvbuf = IDM_RCVBUF_SIZE;
729 729 int32_t sndbuf = IDM_SNDBUF_SIZE;
730 730 const int on = 1;
731 731
732 732 /* Set connect options */
733 733 (void) ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVBUF,
734 734 (char *)&rcvbuf, sizeof (int), CRED());
735 735 (void) ksocket_setsockopt(ks, SOL_SOCKET, SO_SNDBUF,
736 736 (char *)&sndbuf, sizeof (int), CRED());
737 737 (void) ksocket_setsockopt(ks, IPPROTO_TCP, TCP_NODELAY,
738 738 (char *)&on, sizeof (on), CRED());
739 739 }
740 740
741 741 static uint32_t
742 742 n2h24(const uchar_t *ptr)
743 743 {
744 744 return ((ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
745 745 }
746 746
747 747
748 748 static idm_status_t
749 749 idm_sorecvhdr(idm_conn_t *ic, idm_pdu_t *pdu)
750 750 {
751 751 iscsi_hdr_t *bhs;
752 752 uint32_t hdr_digest_crc;
753 753 uint32_t crc_calculated;
754 754 void *new_hdr;
755 755 int ahslen = 0;
756 756 int total_len = 0;
757 757 int iovlen = 0;
758 758 struct iovec iov[2];
759 759 idm_so_conn_t *so_conn;
760 760 int rc;
761 761
762 762 so_conn = ic->ic_transport_private;
763 763
764 764 /*
765 765 * Read BHS
766 766 */
767 767 bhs = pdu->isp_hdr;
768 768 rc = idm_sorecv(so_conn->ic_so, pdu->isp_hdr, sizeof (iscsi_hdr_t));
769 769 if (rc != IDM_STATUS_SUCCESS) {
770 770 return (IDM_STATUS_FAIL);
771 771 }
772 772
773 773 /*
774 774 * Check actual AHS length against the amount available in the buffer
775 775 */
776 776 pdu->isp_hdrlen = sizeof (iscsi_hdr_t) +
777 777 (bhs->hlength * sizeof (uint32_t));
778 778 pdu->isp_datalen = n2h24(bhs->dlength);
779 779 if (ic->ic_conn_type == CONN_TYPE_TGT &&
780 780 pdu->isp_datalen > ic->ic_conn_params.max_recv_dataseglen) {
781 781 IDM_CONN_LOG(CE_WARN,
782 782 "idm_sorecvhdr: exceeded the max data segment length");
783 783 return (IDM_STATUS_FAIL);
784 784 }
785 785 if (bhs->hlength > IDM_SORX_CACHE_AHSLEN) {
786 786 /* Allocate a new header segment and change the callback */
787 787 new_hdr = kmem_alloc(pdu->isp_hdrlen, KM_SLEEP);
788 788 bcopy(pdu->isp_hdr, new_hdr, sizeof (iscsi_hdr_t));
789 789 pdu->isp_hdr = new_hdr;
790 790 pdu->isp_flags |= IDM_PDU_ADDL_HDR;
791 791
792 792 /*
793 793 * This callback will restore the expected values after
794 794 * the RX PDU has been processed.
795 795 */
796 796 pdu->isp_callback = idm_sorx_addl_pdu_cb;
797 797 }
798 798
799 799 /*
800 800 * Setup receipt of additional header and header digest (if enabled).
801 801 */
802 802 if (bhs->hlength > 0) {
803 803 iov[iovlen].iov_base = (caddr_t)(pdu->isp_hdr + 1);
804 804 ahslen = pdu->isp_hdrlen - sizeof (iscsi_hdr_t);
805 805 iov[iovlen].iov_len = ahslen;
806 806 total_len += iov[iovlen].iov_len;
807 807 iovlen++;
808 808 }
809 809
810 810 if (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST) {
811 811 iov[iovlen].iov_base = (caddr_t)&hdr_digest_crc;
812 812 iov[iovlen].iov_len = sizeof (hdr_digest_crc);
813 813 total_len += iov[iovlen].iov_len;
814 814 iovlen++;
815 815 }
816 816
817 817 if ((iovlen != 0) &&
818 818 (idm_iov_sorecv(so_conn->ic_so, &iov[0], iovlen,
819 819 total_len) != 0)) {
820 820 return (IDM_STATUS_FAIL);
821 821 }
822 822
823 823 /*
824 824 * Validate header digest if enabled
825 825 */
826 826 if (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST) {
827 827 crc_calculated = idm_crc32c(pdu->isp_hdr,
828 828 sizeof (iscsi_hdr_t) + ahslen);
829 829 if (crc_calculated != hdr_digest_crc) {
830 830 /* Invalid Header Digest */
831 831 return (IDM_STATUS_HEADER_DIGEST);
832 832 }
833 833 }
834 834
835 835 return (0);
836 836 }
837 837
838 838 /*
839 839 * idm_so_ini_conn_create()
840 840 * Allocate the sockets transport connection resources.
841 841 */
842 842 static idm_status_t
843 843 idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic)
844 844 {
845 845 ksocket_t so;
846 846 idm_so_conn_t *so_conn;
847 847 idm_status_t idmrc;
848 848
849 849 so = idm_socreate(cr->cr_domain, cr->cr_type,
850 850 cr->cr_protocol);
851 851 if (so == NULL) {
852 852 return (IDM_STATUS_FAIL);
853 853 }
854 854
855 855 /* Bind the socket if configured to do so */
856 856 if (cr->cr_bound) {
857 857 if (ksocket_bind(so, &cr->cr_bound_addr.sin,
858 858 SIZEOF_SOCKADDR(&cr->cr_bound_addr.sin), CRED()) != 0) {
859 859 idm_sodestroy(so);
860 860 return (IDM_STATUS_FAIL);
861 861 }
862 862 }
863 863
864 864 idmrc = idm_so_conn_create_common(ic, so);
865 865 if (idmrc != IDM_STATUS_SUCCESS) {
866 866 idm_soshutdown(so);
867 867 idm_sodestroy(so);
868 868 return (IDM_STATUS_FAIL);
869 869 }
870 870
871 871 so_conn = ic->ic_transport_private;
872 872 /* Set up socket options */
873 873 idm_set_ini_preconnect_options(so_conn, cr->cr_boot_conn);
874 874
875 875 return (IDM_STATUS_SUCCESS);
876 876 }
877 877
878 878 /*
879 879 * idm_so_ini_conn_destroy()
880 880 * Tear down the sockets transport connection resources.
881 881 */
882 882 static void
883 883 idm_so_ini_conn_destroy(idm_conn_t *ic)
884 884 {
885 885 idm_so_conn_destroy_common(ic);
886 886 }
887 887
888 888 /*
889 889 * idm_so_ini_conn_connect()
890 890 * Establish the connection referred to by the handle previously allocated via
891 891 * idm_so_ini_conn_create().
892 892 */
893 893 static idm_status_t
894 894 idm_so_ini_conn_connect(idm_conn_t *ic)
895 895 {
896 896 idm_so_conn_t *so_conn;
897 897 struct sonode *node = NULL;
898 898 int rc;
899 899 clock_t lbolt, conn_login_max, conn_login_interval;
900 900 boolean_t nonblock;
901 901
902 902 so_conn = ic->ic_transport_private;
903 903 nonblock = ic->ic_conn_params.nonblock_socket;
904 904 conn_login_max = ic->ic_conn_params.conn_login_max;
905 905 conn_login_interval = ddi_get_lbolt() +
906 906 SEC_TO_TICK(ic->ic_conn_params.conn_login_interval);
907 907
908 908 if (nonblock == B_TRUE) {
909 909 node = ((struct sonode *)(so_conn->ic_so));
910 910 /* Set to none block socket mode */
911 911 idm_so_socket_set_nonblock(node);
912 912 do {
913 913 rc = ksocket_connect(so_conn->ic_so,
914 914 &ic->ic_ini_dst_addr.sin,
915 915 (SIZEOF_SOCKADDR(&ic->ic_ini_dst_addr.sin)),
916 916 CRED());
917 917 if (rc == 0 || rc == EISCONN) {
918 918 /* socket success or already success */
919 919 rc = IDM_STATUS_SUCCESS;
920 920 break;
921 921 }
922 922 if ((rc == ETIMEDOUT) || (rc == ECONNREFUSED) ||
923 923 (rc == ECONNRESET)) {
924 924 /* socket connection timeout or refuse */
925 925 break;
926 926 }
927 927 lbolt = ddi_get_lbolt();
928 928 if (lbolt > conn_login_max) {
929 929 /*
930 930 * Connection retry timeout,
931 931 * failed connect to target.
932 932 */
933 933 break;
934 934 }
935 935 if (lbolt < conn_login_interval) {
936 936 if ((rc == EINPROGRESS) || (rc == EALREADY)) {
937 937 /* TCP connect still in progress */
938 938 delay(SEC_TO_TICK(IN_PROGRESS_DELAY));
939 939 continue;
940 940 } else {
941 941 delay(conn_login_interval - lbolt);
942 942 }
943 943 }
944 944 conn_login_interval = ddi_get_lbolt() +
945 945 SEC_TO_TICK(ic->ic_conn_params.conn_login_interval);
946 946 } while (rc != 0);
947 947 /* resume to nonblock mode */
948 948 if (rc == IDM_STATUS_SUCCESS) {
949 949 idm_so_socket_set_block(node);
950 950 }
951 951 } else {
952 952 rc = ksocket_connect(so_conn->ic_so, &ic->ic_ini_dst_addr.sin,
953 953 (SIZEOF_SOCKADDR(&ic->ic_ini_dst_addr.sin)), CRED());
954 954 }
955 955
956 956 if (rc != 0) {
957 957 idm_soshutdown(so_conn->ic_so);
958 958 return (IDM_STATUS_FAIL);
959 959 }
960 960
961 961 idm_so_conn_connect_common(ic);
962 962
963 963 idm_set_ini_postconnect_options(so_conn);
964 964
965 965 return (IDM_STATUS_SUCCESS);
966 966 }
967 967
968 968 idm_status_t
969 969 idm_so_tgt_conn_create(idm_conn_t *ic, ksocket_t new_so)
970 970 {
971 971 idm_status_t idmrc;
972 972
973 973 idmrc = idm_so_conn_create_common(ic, new_so);
974 974
975 975 return (idmrc);
976 976 }
977 977
978 978 static void
979 979 idm_so_tgt_conn_destroy(idm_conn_t *ic)
980 980 {
981 981 idm_so_conn_destroy_common(ic);
982 982 }
983 983
984 984 /*
985 985 * idm_so_tgt_conn_connect()
986 986 * Establish the connection in ic, passed from idm_tgt_conn_finish(), which
987 987 * is invoked from the SM as a result of an inbound connection request.
988 988 */
989 989 static idm_status_t
990 990 idm_so_tgt_conn_connect(idm_conn_t *ic)
991 991 {
992 992 idm_so_conn_connect_common(ic);
993 993
994 994 return (IDM_STATUS_SUCCESS);
995 995 }
996 996
997 997 static idm_status_t
998 998 idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so)
999 999 {
1000 1000 idm_so_conn_t *so_conn;
1001 1001
1002 1002 so_conn = kmem_zalloc(sizeof (idm_so_conn_t), KM_SLEEP);
1003 1003 so_conn->ic_so = new_so;
1004 1004
1005 1005 ic->ic_transport_private = so_conn;
1006 1006 ic->ic_transport_hdrlen = 0;
1007 1007
1008 1008 /* Set the scoreboarding flag on this connection */
1009 1009 ic->ic_conn_flags |= IDM_CONN_USE_SCOREBOARD;
1010 1010 ic->ic_conn_params.max_recv_dataseglen =
1011 1011 ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
1012 1012 ic->ic_conn_params.max_xmit_dataseglen =
1013 1013 ISCSI_DEFAULT_MAX_XMIT_SEG_LEN;
1014 1014
1015 1015 /*
1016 1016 * Initialize tx thread mutex and list
1017 1017 */
1018 1018 mutex_init(&so_conn->ic_tx_mutex, NULL, MUTEX_DEFAULT, NULL);
1019 1019 cv_init(&so_conn->ic_tx_cv, NULL, CV_DEFAULT, NULL);
1020 1020 list_create(&so_conn->ic_tx_list, sizeof (idm_pdu_t),
1021 1021 offsetof(idm_pdu_t, idm_tx_link));
1022 1022
1023 1023 return (IDM_STATUS_SUCCESS);
1024 1024 }
1025 1025
1026 1026 static void
1027 1027 idm_so_conn_destroy_common(idm_conn_t *ic)
1028 1028 {
1029 1029 idm_so_conn_t *so_conn = ic->ic_transport_private;
1030 1030
1031 1031 ic->ic_transport_private = NULL;
1032 1032 idm_sodestroy(so_conn->ic_so);
1033 1033 list_destroy(&so_conn->ic_tx_list);
1034 1034 mutex_destroy(&so_conn->ic_tx_mutex);
1035 1035 cv_destroy(&so_conn->ic_tx_cv);
1036 1036
1037 1037 kmem_free(so_conn, sizeof (idm_so_conn_t));
1038 1038 }
1039 1039
1040 1040 static void
1041 1041 idm_so_conn_connect_common(idm_conn_t *ic)
1042 1042 {
1043 1043 idm_so_conn_t *so_conn;
1044 1044 struct sockaddr_in6 t_addr;
1045 1045 socklen_t t_addrlen = 0;
1046 1046
1047 1047 so_conn = ic->ic_transport_private;
1048 1048 bzero(&t_addr, sizeof (struct sockaddr_in6));
1049 1049 t_addrlen = sizeof (struct sockaddr_in6);
1050 1050
1051 1051 /* Set the local and remote addresses in the idm conn handle */
1052 1052 (void) ksocket_getsockname(so_conn->ic_so, (struct sockaddr *)&t_addr,
1053 1053 &t_addrlen, CRED());
1054 1054 bcopy(&t_addr, &ic->ic_laddr, t_addrlen);
1055 1055 (void) ksocket_getpeername(so_conn->ic_so, (struct sockaddr *)&t_addr,
1056 1056 &t_addrlen, CRED());
1057 1057 bcopy(&t_addr, &ic->ic_raddr, t_addrlen);
1058 1058
1059 1059 mutex_enter(&ic->ic_mutex);
1060 1060 so_conn->ic_tx_thread = thread_create(NULL, 0, idm_sotx_thread, ic, 0,
1061 1061 &p0, TS_RUN, minclsyspri);
1062 1062 so_conn->ic_rx_thread = thread_create(NULL, 0, idm_sorx_thread, ic, 0,
1063 1063 &p0, TS_RUN, minclsyspri);
1064 1064
1065 1065 while (so_conn->ic_rx_thread_did == 0 ||
1066 1066 so_conn->ic_tx_thread_did == 0)
1067 1067 cv_wait(&ic->ic_cv, &ic->ic_mutex);
1068 1068 mutex_exit(&ic->ic_mutex);
1069 1069 }
1070 1070
1071 1071 /*
1072 1072 * idm_so_conn_disconnect()
1073 1073 * Shutdown the socket connection and stop the thread
1074 1074 */
1075 1075 static void
1076 1076 idm_so_conn_disconnect(idm_conn_t *ic)
1077 1077 {
1078 1078 idm_so_conn_t *so_conn;
1079 1079
1080 1080 so_conn = ic->ic_transport_private;
1081 1081
1082 1082 mutex_enter(&ic->ic_mutex);
1083 1083 so_conn->ic_rx_thread_running = B_FALSE;
1084 1084 so_conn->ic_tx_thread_running = B_FALSE;
1085 1085 /* We need to wakeup the TX thread */
1086 1086 mutex_enter(&so_conn->ic_tx_mutex);
1087 1087 cv_signal(&so_conn->ic_tx_cv);
1088 1088 mutex_exit(&so_conn->ic_tx_mutex);
1089 1089 mutex_exit(&ic->ic_mutex);
1090 1090
1091 1091 /* This should wakeup the RX thread if it is sleeping */
1092 1092 idm_soshutdown(so_conn->ic_so);
1093 1093
1094 1094 thread_join(so_conn->ic_tx_thread_did);
1095 1095 thread_join(so_conn->ic_rx_thread_did);
1096 1096 }
1097 1097
1098 1098 /*
1099 1099 * idm_so_tgt_svc_create()
1100 1100 * Establish a service on an IP address and port. idm_svc_req_t contains
1101 1101 * the service parameters.
1102 1102 */
1103 1103 /*ARGSUSED*/
1104 1104 static idm_status_t
1105 1105 idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is)
1106 1106 {
1107 1107 idm_so_svc_t *so_svc;
1108 1108
1109 1109 so_svc = kmem_zalloc(sizeof (idm_so_svc_t), KM_SLEEP);
1110 1110
1111 1111 /* Set the new sockets service in svc handle */
1112 1112 is->is_so_svc = (void *)so_svc;
1113 1113
1114 1114 return (IDM_STATUS_SUCCESS);
1115 1115 }
1116 1116
1117 1117 /*
1118 1118 * idm_so_tgt_svc_destroy()
1119 1119 * Teardown sockets resources allocated in idm_so_tgt_svc_create()
1120 1120 */
1121 1121 static void
1122 1122 idm_so_tgt_svc_destroy(idm_svc_t *is)
1123 1123 {
1124 1124 /* the socket will have been torn down; free the service */
1125 1125 kmem_free(is->is_so_svc, sizeof (idm_so_svc_t));
1126 1126 }
1127 1127
1128 1128 /*
1129 1129 * idm_so_tgt_svc_online()
1130 1130 * Launch a watch thread on the svc allocated in idm_so_tgt_svc_create()
1131 1131 */
1132 1132
1133 1133 static idm_status_t
1134 1134 idm_so_tgt_svc_online(idm_svc_t *is)
1135 1135 {
1136 1136 idm_so_svc_t *so_svc;
1137 1137 idm_svc_req_t *sr = &is->is_svc_req;
1138 1138 struct sockaddr_in6 sin6_ip;
1139 1139 const uint32_t on = 1;
1140 1140 const uint32_t off = 0;
1141 1141
1142 1142 mutex_enter(&is->is_mutex);
1143 1143 so_svc = (idm_so_svc_t *)is->is_so_svc;
1144 1144
1145 1145 /*
1146 1146 * Try creating an IPv6 socket first
1147 1147 */
1148 1148 if ((so_svc->is_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) == NULL) {
1149 1149 mutex_exit(&is->is_mutex);
1150 1150 return (IDM_STATUS_FAIL);
1151 1151 } else {
1152 1152 bzero(&sin6_ip, sizeof (sin6_ip));
1153 1153 sin6_ip.sin6_family = AF_INET6;
1154 1154 sin6_ip.sin6_port = htons(sr->sr_port);
1155 1155 sin6_ip.sin6_addr = in6addr_any;
1156 1156
1157 1157 (void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET,
1158 1158 SO_REUSEADDR, (char *)&on, sizeof (on), CRED());
1159 1159 /*
1160 1160 * Turn off SO_MAC_EXEMPT so future sobinds succeed
1161 1161 */
1162 1162 (void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET,
1163 1163 SO_MAC_EXEMPT, (char *)&off, sizeof (off), CRED());
1164 1164
1165 1165 if (ksocket_bind(so_svc->is_so, (struct sockaddr *)&sin6_ip,
1166 1166 sizeof (sin6_ip), CRED()) != 0) {
1167 1167 mutex_exit(&is->is_mutex);
1168 1168 idm_sodestroy(so_svc->is_so);
1169 1169 return (IDM_STATUS_FAIL);
1170 1170 }
1171 1171 }
1172 1172
1173 1173 idm_set_tgt_connect_options(so_svc->is_so);
1174 1174
1175 1175 if (ksocket_listen(so_svc->is_so, 5, CRED()) != 0) {
1176 1176 mutex_exit(&is->is_mutex);
1177 1177 idm_soshutdown(so_svc->is_so);
1178 1178 idm_sodestroy(so_svc->is_so);
1179 1179 return (IDM_STATUS_FAIL);
1180 1180 }
1181 1181
1182 1182 /* Launch a watch thread */
1183 1183 so_svc->is_thread = thread_create(NULL, 0, idm_so_svc_port_watcher,
1184 1184 is, 0, &p0, TS_RUN, minclsyspri);
1185 1185
1186 1186 if (so_svc->is_thread == NULL) {
1187 1187 /* Failure to launch; teardown the socket */
1188 1188 mutex_exit(&is->is_mutex);
1189 1189 idm_soshutdown(so_svc->is_so);
1190 1190 idm_sodestroy(so_svc->is_so);
1191 1191 return (IDM_STATUS_FAIL);
1192 1192 }
1193 1193 ksocket_hold(so_svc->is_so);
1194 1194 /* Wait for the port watcher thread to start */
1195 1195 while (!so_svc->is_thread_running)
1196 1196 cv_wait(&is->is_cv, &is->is_mutex);
1197 1197 mutex_exit(&is->is_mutex);
1198 1198
1199 1199 return (IDM_STATUS_SUCCESS);
1200 1200 }
1201 1201
1202 1202 /*
1203 1203 * idm_so_tgt_svc_offline
1204 1204 *
1205 1205 * Stop listening on the IP address and port identified by idm_svc_t.
1206 1206 */
1207 1207 static void
1208 1208 idm_so_tgt_svc_offline(idm_svc_t *is)
1209 1209 {
1210 1210 idm_so_svc_t *so_svc;
1211 1211 mutex_enter(&is->is_mutex);
1212 1212 so_svc = (idm_so_svc_t *)is->is_so_svc;
1213 1213 so_svc->is_thread_running = B_FALSE;
1214 1214 mutex_exit(&is->is_mutex);
1215 1215
1216 1216 /*
1217 1217 * Teardown socket
1218 1218 */
1219 1219 idm_sodestroy(so_svc->is_so);
1220 1220
1221 1221 /*
1222 1222 * Now we expect the port watcher thread to terminate
1223 1223 */
1224 1224 thread_join(so_svc->is_thread_did);
1225 1225 }
1226 1226
1227 1227 /*
1228 1228 * Watch thread for target service connection establishment.
1229 1229 */
1230 1230 void
1231 1231 idm_so_svc_port_watcher(void *arg)
1232 1232 {
1233 1233 idm_svc_t *svc = arg;
1234 1234 ksocket_t new_so;
1235 1235 idm_conn_t *ic;
1236 1236 idm_status_t idmrc;
1237 1237 idm_so_svc_t *so_svc;
1238 1238 int rc;
1239 1239 const uint32_t off = 0;
1240 1240 struct sockaddr_in6 t_addr;
1241 1241 socklen_t t_addrlen;
1242 1242
1243 1243 bzero(&t_addr, sizeof (struct sockaddr_in6));
1244 1244 t_addrlen = sizeof (struct sockaddr_in6);
1245 1245 mutex_enter(&svc->is_mutex);
1246 1246
1247 1247 so_svc = svc->is_so_svc;
1248 1248 so_svc->is_thread_running = B_TRUE;
1249 1249 so_svc->is_thread_did = so_svc->is_thread->t_did;
1250 1250
1251 1251 cv_signal(&svc->is_cv);
1252 1252
|
↓ open down ↓ |
1252 lines elided |
↑ open up ↑ |
1253 1253 IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) online", (void *)svc,
1254 1254 svc->is_svc_req.sr_port);
1255 1255
1256 1256 while (so_svc->is_thread_running) {
1257 1257 mutex_exit(&svc->is_mutex);
1258 1258
1259 1259 if ((rc = ksocket_accept(so_svc->is_so,
1260 1260 (struct sockaddr *)&t_addr, &t_addrlen,
1261 1261 &new_so, CRED())) != 0) {
1262 1262 mutex_enter(&svc->is_mutex);
1263 - if (rc == ECONNABORTED)
1264 - continue;
1265 - /* Connection problem */
1266 - break;
1263 + if (rc != ECONNABORTED && rc != EINTR) {
1264 + IDM_SVC_LOG(CE_NOTE, "idm_so_svc_port_watcher:"
1265 + " ksocket_accept failed %d", rc);
1266 + }
1267 + /*
1268 + * Unclean shutdown of this thread is not handled
1269 + * wait for !is_thread_running.
1270 + */
1271 + continue;
1267 1272 }
1268 1273 /*
1269 1274 * Turn off SO_MAC_EXEMPT so future sobinds succeed
1270 1275 */
1271 1276 (void) ksocket_setsockopt(new_so, SOL_SOCKET, SO_MAC_EXEMPT,
1272 1277 (char *)&off, sizeof (off), CRED());
1273 1278
1274 1279 idmrc = idm_svc_conn_create(svc, IDM_TRANSPORT_TYPE_SOCKETS,
1275 1280 &ic);
1276 1281 if (idmrc != IDM_STATUS_SUCCESS) {
1277 1282 /* Drop connection */
1278 1283 idm_soshutdown(new_so);
1279 1284 idm_sodestroy(new_so);
1280 1285 mutex_enter(&svc->is_mutex);
1281 1286 continue;
1282 1287 }
1283 1288
1284 1289 idmrc = idm_so_tgt_conn_create(ic, new_so);
1285 1290 if (idmrc != IDM_STATUS_SUCCESS) {
1286 1291 idm_svc_conn_destroy(ic);
1287 1292 idm_soshutdown(new_so);
1288 1293 idm_sodestroy(new_so);
1289 1294 mutex_enter(&svc->is_mutex);
1290 1295 continue;
1291 1296 }
1292 1297
1293 1298 /*
1294 1299 * Kick the state machine. At CS_S3_XPT_UP the state machine
1295 1300 * will notify the client (target) about the new connection.
1296 1301 */
1297 1302 idm_conn_event(ic, CE_CONNECT_ACCEPT, NULL);
1298 1303
1299 1304 mutex_enter(&svc->is_mutex);
1300 1305 }
1301 1306 ksocket_rele(so_svc->is_so);
1302 1307 so_svc->is_thread_running = B_FALSE;
1303 1308 mutex_exit(&svc->is_mutex);
1304 1309
1305 1310 IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) offline", (void *)svc,
1306 1311 svc->is_svc_req.sr_port);
1307 1312
1308 1313 thread_exit();
1309 1314 }
1310 1315
1311 1316 /*
1312 1317 * idm_so_free_task_rsrc() stops any ongoing processing of the task and
1313 1318 * frees resources associated with the task.
1314 1319 *
1315 1320 * It's not clear that this should return idm_status_t. What do we do
1316 1321 * if it fails?
1317 1322 */
1318 1323 static idm_status_t
1319 1324 idm_so_free_task_rsrc(idm_task_t *idt)
1320 1325 {
1321 1326 idm_buf_t *idb, *next_idb;
1322 1327
1323 1328 /*
1324 1329 * There is nothing to cleanup on initiator connections
1325 1330 */
1326 1331 if (IDM_CONN_ISINI(idt->idt_ic))
1327 1332 return (IDM_STATUS_SUCCESS);
1328 1333
1329 1334 /*
1330 1335 * If this is a target connection, call idm_buf_rx_from_ini_done for
1331 1336 * any buffer on the "outbufv" list with idb->idb_in_transport==B_TRUE.
1332 1337 *
1333 1338 * In addition, remove any buffers associated with this task from
1334 1339 * the ic_tx_list. We'll do this by walking the idt_inbufv list, but
1335 1340 * items don't actually get removed from that list (and completion
1336 1341 * routines called) until idm_task_cleanup.
1337 1342 */
1338 1343 mutex_enter(&idt->idt_mutex);
1339 1344
1340 1345 for (idb = list_head(&idt->idt_outbufv); idb != NULL; idb = next_idb) {
1341 1346 next_idb = list_next(&idt->idt_outbufv, idb);
1342 1347 if (idb->idb_in_transport) {
1343 1348 /*
1344 1349 * idm_buf_rx_from_ini_done releases idt->idt_mutex
1345 1350 */
1346 1351 DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1347 1352 uintptr_t, idb->idb_buf,
1348 1353 uint32_t, idb->idb_bufoffset,
1349 1354 uint64_t, 0, uint32_t, 0, uint32_t, 0,
1350 1355 uint32_t, idb->idb_xfer_len,
1351 1356 int, XFER_BUF_RX_FROM_INI);
1352 1357 idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_ABORTED);
1353 1358 mutex_enter(&idt->idt_mutex);
1354 1359 }
1355 1360 }
1356 1361
1357 1362 for (idb = list_head(&idt->idt_inbufv); idb != NULL; idb = next_idb) {
1358 1363 next_idb = list_next(&idt->idt_inbufv, idb);
1359 1364 /*
1360 1365 * We want to remove these items from the tx_list as well,
1361 1366 * but knowing it's in the idt_inbufv list is not a guarantee
1362 1367 * that it's in the tx_list. If it's on the tx list then
1363 1368 * let idm_sotx_thread() clean it up.
1364 1369 */
1365 1370 if (idb->idb_in_transport && !idb->idb_tx_thread) {
1366 1371 /*
1367 1372 * idm_buf_tx_to_ini_done releases idt->idt_mutex
1368 1373 */
1369 1374 DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1370 1375 uintptr_t, idb->idb_buf,
1371 1376 uint32_t, idb->idb_bufoffset,
1372 1377 uint64_t, 0, uint32_t, 0, uint32_t, 0,
1373 1378 uint32_t, idb->idb_xfer_len,
1374 1379 int, XFER_BUF_TX_TO_INI);
1375 1380 idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED);
1376 1381 mutex_enter(&idt->idt_mutex);
1377 1382 }
1378 1383 }
1379 1384
1380 1385 mutex_exit(&idt->idt_mutex);
1381 1386
1382 1387 return (IDM_STATUS_SUCCESS);
1383 1388 }
1384 1389
1385 1390 /*
1386 1391 * idm_so_negotiate_key_values() validates the key values for this connection
1387 1392 */
1388 1393 /* ARGSUSED */
1389 1394 static kv_status_t
1390 1395 idm_so_negotiate_key_values(idm_conn_t *it, nvlist_t *request_nvl,
1391 1396 nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
1392 1397 {
1393 1398 /* All parameters are negotiated at the iscsit level */
1394 1399 return (KV_HANDLED);
1395 1400 }
1396 1401
1397 1402 /*
1398 1403 * idm_so_notice_key_values() activates the negotiated key values for
1399 1404 * this connection.
1400 1405 */
1401 1406 static void
1402 1407 idm_so_notice_key_values(idm_conn_t *it, nvlist_t *negotiated_nvl)
1403 1408 {
1404 1409 char *nvp_name;
1405 1410 nvpair_t *nvp;
1406 1411 nvpair_t *next_nvp;
1407 1412 int nvrc;
1408 1413 idm_status_t idm_status;
1409 1414 const idm_kv_xlate_t *ikvx;
1410 1415 uint64_t num_val;
1411 1416
1412 1417 for (nvp = nvlist_next_nvpair(negotiated_nvl, NULL);
1413 1418 nvp != NULL; nvp = next_nvp) {
1414 1419 next_nvp = nvlist_next_nvpair(negotiated_nvl, nvp);
1415 1420 nvp_name = nvpair_name(nvp);
1416 1421
1417 1422 ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
1418 1423 switch (ikvx->ik_key_id) {
1419 1424 case KI_HEADER_DIGEST:
1420 1425 case KI_DATA_DIGEST:
1421 1426 idm_status = idm_so_handle_digest(it, nvp, ikvx);
1422 1427 ASSERT(idm_status == 0);
1423 1428
1424 1429 /* Remove processed item from negotiated_nvl list */
1425 1430 nvrc = nvlist_remove_all(
1426 1431 negotiated_nvl, ikvx->ik_key_name);
1427 1432 ASSERT(nvrc == 0);
1428 1433 break;
1429 1434 case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
1430 1435 /*
1431 1436 * Just pass the value down to idm layer.
1432 1437 * No need to remove it from negotiated_nvl list here.
1433 1438 */
1434 1439 nvrc = nvpair_value_uint64(nvp, &num_val);
1435 1440 ASSERT(nvrc == 0);
1436 1441 it->ic_conn_params.max_xmit_dataseglen =
1437 1442 (uint32_t)num_val;
1438 1443 break;
1439 1444 default:
1440 1445 break;
1441 1446 }
1442 1447 }
1443 1448 }
1444 1449
1445 1450 /*
1446 1451 * idm_so_declare_key_values() declares the key values for this connection
1447 1452 */
1448 1453 /* ARGSUSED */
1449 1454 static kv_status_t
1450 1455 idm_so_declare_key_values(idm_conn_t *it, nvlist_t *config_nvl,
1451 1456 nvlist_t *outgoing_nvl)
1452 1457 {
1453 1458 char *nvp_name;
1454 1459 nvpair_t *nvp;
1455 1460 nvpair_t *next_nvp;
1456 1461 kv_status_t kvrc;
1457 1462 int nvrc = 0;
1458 1463 const idm_kv_xlate_t *ikvx;
1459 1464 uint64_t num_val;
1460 1465
1461 1466 for (nvp = nvlist_next_nvpair(config_nvl, NULL);
1462 1467 nvp != NULL && nvrc == 0; nvp = next_nvp) {
1463 1468 next_nvp = nvlist_next_nvpair(config_nvl, nvp);
1464 1469 nvp_name = nvpair_name(nvp);
1465 1470
1466 1471 ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
1467 1472 switch (ikvx->ik_key_id) {
1468 1473 case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
1469 1474 if ((nvrc = nvpair_value_uint64(nvp, &num_val)) != 0) {
1470 1475 break;
1471 1476 }
1472 1477 if (outgoing_nvl &&
1473 1478 (nvrc = nvlist_add_uint64(outgoing_nvl,
1474 1479 nvp_name, num_val)) != 0) {
1475 1480 break;
1476 1481 }
1477 1482 it->ic_conn_params.max_recv_dataseglen =
1478 1483 (uint32_t)num_val;
1479 1484 break;
1480 1485 default:
1481 1486 break;
1482 1487 }
1483 1488 }
1484 1489 kvrc = idm_nvstat_to_kvstat(nvrc);
1485 1490 return (kvrc);
1486 1491 }
1487 1492
1488 1493 static idm_status_t
1489 1494 idm_so_handle_digest(idm_conn_t *it, nvpair_t *digest_choice,
1490 1495 const idm_kv_xlate_t *ikvx)
1491 1496 {
1492 1497 int nvrc;
1493 1498 char *digest_choice_string;
1494 1499
1495 1500 nvrc = nvpair_value_string(digest_choice,
1496 1501 &digest_choice_string);
1497 1502 ASSERT(nvrc == 0);
1498 1503 if (strcasecmp(digest_choice_string, "crc32c") == 0) {
1499 1504 switch (ikvx->ik_key_id) {
1500 1505 case KI_HEADER_DIGEST:
1501 1506 it->ic_conn_flags |= IDM_CONN_HEADER_DIGEST;
1502 1507 break;
1503 1508 case KI_DATA_DIGEST:
1504 1509 it->ic_conn_flags |= IDM_CONN_DATA_DIGEST;
1505 1510 break;
1506 1511 default:
1507 1512 ASSERT(0);
1508 1513 break;
1509 1514 }
1510 1515 } else if (strcasecmp(digest_choice_string, "none") == 0) {
1511 1516 switch (ikvx->ik_key_id) {
1512 1517 case KI_HEADER_DIGEST:
1513 1518 it->ic_conn_flags &= ~IDM_CONN_HEADER_DIGEST;
1514 1519 break;
1515 1520 case KI_DATA_DIGEST:
1516 1521 it->ic_conn_flags &= ~IDM_CONN_DATA_DIGEST;
1517 1522 break;
1518 1523 default:
1519 1524 ASSERT(0);
1520 1525 break;
1521 1526 }
1522 1527 } else {
1523 1528 ASSERT(0);
1524 1529 }
1525 1530
1526 1531 return (IDM_STATUS_SUCCESS);
1527 1532 }
1528 1533
1529 1534
1530 1535 /*
1531 1536 * idm_so_conn_is_capable() verifies that the passed connection is provided
1532 1537 * for by the sockets interface.
1533 1538 */
1534 1539 /* ARGSUSED */
1535 1540 static boolean_t
1536 1541 idm_so_conn_is_capable(idm_conn_req_t *ic, idm_transport_caps_t *caps)
1537 1542 {
1538 1543 return (B_TRUE);
1539 1544 }
1540 1545
1541 1546 /*
1542 1547 * idm_so_rx_datain() validates the Data Sequence number of the PDU. The
1543 1548 * idm_sorecv_scsidata() function invoked earlier actually reads the data
1544 1549 * off the socket into the appropriate buffers.
1545 1550 */
1546 1551 static void
1547 1552 idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu)
1548 1553 {
1549 1554 iscsi_data_hdr_t *bhs;
1550 1555 idm_task_t *idt;
1551 1556 idm_buf_t *idb;
1552 1557 uint32_t datasn;
1553 1558 size_t offset;
1554 1559 iscsi_hdr_t *ihp = (iscsi_hdr_t *)pdu->isp_hdr;
1555 1560 iscsi_data_rsp_hdr_t *idrhp = (iscsi_data_rsp_hdr_t *)ihp;
1556 1561
1557 1562 ASSERT(ic != NULL);
1558 1563 ASSERT(pdu != NULL);
1559 1564
1560 1565 bhs = (iscsi_data_hdr_t *)pdu->isp_hdr;
1561 1566 datasn = ntohl(bhs->datasn);
1562 1567 offset = ntohl(bhs->offset);
1563 1568
1564 1569 ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA_RSP);
1565 1570
1566 1571 /*
1567 1572 * Look up the task corresponding to the initiator task tag
1568 1573 * to get the buffers affiliated with the task.
1569 1574 */
1570 1575 idt = idm_task_find(ic, bhs->itt, bhs->ttt);
1571 1576 if (idt == NULL) {
1572 1577 IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: failed to find task");
1573 1578 idm_pdu_rx_protocol_error(ic, pdu);
1574 1579 return;
1575 1580 }
1576 1581
1577 1582 idb = pdu->isp_sorx_buf;
1578 1583 if (idb == NULL) {
1579 1584 IDM_CONN_LOG(CE_WARN,
1580 1585 "idm_so_rx_datain: failed to find buffer");
1581 1586 idm_task_rele(idt);
1582 1587 idm_pdu_rx_protocol_error(ic, pdu);
1583 1588 return;
1584 1589 }
1585 1590
1586 1591 /*
1587 1592 * DataSN values should be sequential and should not have any gaps or
1588 1593 * repetitions. Check the DataSN with the one stored in the task.
1589 1594 */
1590 1595 if (datasn == idt->idt_exp_datasn) {
1591 1596 idt->idt_exp_datasn++; /* keep track of DataSN received */
1592 1597 } else {
1593 1598 IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: datasn out of order");
1594 1599 idm_task_rele(idt);
1595 1600 idm_pdu_rx_protocol_error(ic, pdu);
1596 1601 return;
1597 1602 }
1598 1603
1599 1604 /*
1600 1605 * PDUs in a sequence should be in continuously increasing
1601 1606 * address offset
1602 1607 */
1603 1608 if (offset != idb->idb_exp_offset) {
1604 1609 IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: unexpected offset");
1605 1610 idm_task_rele(idt);
1606 1611 idm_pdu_rx_protocol_error(ic, pdu);
1607 1612 return;
1608 1613 }
1609 1614 /* Expected next relative buffer offset */
1610 1615 idb->idb_exp_offset += n2h24(bhs->dlength);
1611 1616 idt->idt_rx_bytes += n2h24(bhs->dlength);
1612 1617
1613 1618 idm_task_rele(idt);
1614 1619
1615 1620 /*
1616 1621 * For now call scsi_rsp which will process the data rsp
1617 1622 * Revisit, need to provide an explicit client entry point for
1618 1623 * phase collapse completions.
1619 1624 */
1620 1625 if (((ihp->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_DATA_RSP) &&
1621 1626 (idrhp->flags & ISCSI_FLAG_DATA_STATUS)) {
1622 1627 (*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu);
1623 1628 }
1624 1629
1625 1630 idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1626 1631 }
1627 1632
1628 1633 /*
1629 1634 * The idm_so_rx_dataout() function is used by the iSCSI target to read
1630 1635 * data from the Data-Out PDU sent by the iSCSI initiator.
1631 1636 *
1632 1637 * This function gets the Initiator Task Tag from the PDU BHS and looks up the
1633 1638 * task to get the buffers associated with the PDU. A PDU might span buffers.
1634 1639 * The data is then read into the respective buffer.
1635 1640 */
1636 1641 static void
1637 1642 idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu)
1638 1643 {
1639 1644
1640 1645 iscsi_data_hdr_t *bhs;
1641 1646 idm_task_t *idt;
1642 1647 idm_buf_t *idb;
1643 1648 size_t offset;
1644 1649
1645 1650 ASSERT(ic != NULL);
1646 1651 ASSERT(pdu != NULL);
1647 1652
1648 1653 bhs = (iscsi_data_hdr_t *)pdu->isp_hdr;
1649 1654 offset = ntohl(bhs->offset);
1650 1655 ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA);
1651 1656
1652 1657 /*
1653 1658 * Look up the task corresponding to the initiator task tag
1654 1659 * to get the buffers affiliated with the task.
1655 1660 */
1656 1661 idt = idm_task_find(ic, bhs->itt, bhs->ttt);
1657 1662 if (idt == NULL) {
1658 1663 IDM_CONN_LOG(CE_WARN,
1659 1664 "idm_so_rx_dataout: failed to find task");
1660 1665 idm_pdu_rx_protocol_error(ic, pdu);
1661 1666 return;
1662 1667 }
1663 1668
1664 1669 idb = pdu->isp_sorx_buf;
1665 1670 if (idb == NULL) {
1666 1671 IDM_CONN_LOG(CE_WARN,
1667 1672 "idm_so_rx_dataout: failed to find buffer");
1668 1673 idm_task_rele(idt);
1669 1674 idm_pdu_rx_protocol_error(ic, pdu);
1670 1675 return;
1671 1676 }
1672 1677
1673 1678 /* Keep track of data transferred - check data offsets */
1674 1679 if (offset != idb->idb_exp_offset) {
1675 1680 IDM_CONN_LOG(CE_NOTE, "idm_so_rx_dataout: offset out of seq: "
1676 1681 "%ld, %d", offset, idb->idb_exp_offset);
1677 1682 idm_task_rele(idt);
1678 1683 idm_pdu_rx_protocol_error(ic, pdu);
1679 1684 return;
1680 1685 }
1681 1686 /* Expected next relative offset */
1682 1687 idb->idb_exp_offset += ntoh24(bhs->dlength);
1683 1688 idt->idt_rx_bytes += n2h24(bhs->dlength);
1684 1689
1685 1690 /*
1686 1691 * Call the buffer callback when the transfer is complete
1687 1692 *
1688 1693 * The connection state machine should only abort tasks after
1689 1694 * shutting down the connection so we are assured that there
1690 1695 * won't be a simultaneous attempt to abort this task at the
1691 1696 * same time as we are processing this PDU (due to a connection
1692 1697 * state change).
1693 1698 */
1694 1699 if (bhs->flags & ISCSI_FLAG_FINAL) {
1695 1700 /*
1696 1701 * We only want to call idm_buf_rx_from_ini_done once
1697 1702 * per transfer. It's possible that this task has
1698 1703 * already been aborted in which case
1699 1704 * idm_so_free_task_rsrc will call idm_buf_rx_from_ini_done
1700 1705 * for each buffer with idb_in_transport==B_TRUE. To
1701 1706 * close this window and ensure that this doesn't happen,
1702 1707 * we'll clear idb->idb_in_transport now while holding
1703 1708 * the task mutex. This is only really an issue for
1704 1709 * SCSI task abort -- if tasks were being aborted because
1705 1710 * of a connection state change the state machine would
1706 1711 * have already stopped the receive thread.
1707 1712 */
1708 1713 mutex_enter(&idt->idt_mutex);
1709 1714
1710 1715 /*
1711 1716 * Release the task hold here (obtained in idm_task_find)
1712 1717 * because the task may complete synchronously during
1713 1718 * idm_buf_rx_from_ini_done. Since we still have an active
1714 1719 * buffer we know there is at least one additional hold on idt.
1715 1720 */
1716 1721 idm_task_rele(idt);
1717 1722
1718 1723 /*
1719 1724 * idm_buf_rx_from_ini_done releases idt->idt_mutex
1720 1725 */
1721 1726 DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1722 1727 uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
1723 1728 uint64_t, 0, uint32_t, 0, uint32_t, 0,
1724 1729 uint32_t, idb->idb_xfer_len,
1725 1730 int, XFER_BUF_RX_FROM_INI);
1726 1731 idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_SUCCESS);
1727 1732 idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1728 1733 return;
1729 1734 }
1730 1735
1731 1736 idm_task_rele(idt);
1732 1737 idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1733 1738 }
1734 1739
1735 1740 /*
1736 1741 * The idm_so_rx_rtt() function is used by the iSCSI initiator to handle
1737 1742 * the R2T PDU sent by the iSCSI target indicating that it is ready to
1738 1743 * accept data. This gets the Initiator Task Tag (itt) from the PDU BHS
1739 1744 * and looks up the task in the task tree using the itt to get the output
1740 1745 * buffers associated the task. The R2T PDU contains the offset of the
1741 1746 * requested data and the data length. This function then constructs a
1742 1747 * sequence of iSCSI PDUs and outputs the requested data. Each Data-Out
1743 1748 * PDU is associated with the R2T by the Target Transfer Tag (ttt).
1744 1749 */
1745 1750
1746 1751 static void
1747 1752 idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu)
1748 1753 {
1749 1754 idm_task_t *idt;
1750 1755 idm_buf_t *idb;
1751 1756 iscsi_rtt_hdr_t *rtt_hdr;
1752 1757 uint32_t data_offset;
1753 1758 uint32_t data_length;
1754 1759
1755 1760 ASSERT(ic != NULL);
1756 1761 ASSERT(pdu != NULL);
1757 1762
1758 1763 rtt_hdr = (iscsi_rtt_hdr_t *)pdu->isp_hdr;
1759 1764 data_offset = ntohl(rtt_hdr->data_offset);
1760 1765 data_length = ntohl(rtt_hdr->data_length);
1761 1766 idt = idm_task_find(ic, rtt_hdr->itt, rtt_hdr->ttt);
1762 1767
1763 1768 if (idt == NULL) {
1764 1769 IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find task");
1765 1770 idm_pdu_rx_protocol_error(ic, pdu);
1766 1771 return;
1767 1772 }
1768 1773
1769 1774 /* Find the buffer bound to the task by the iSCSI initiator */
1770 1775 mutex_enter(&idt->idt_mutex);
1771 1776 idb = idm_buf_find(&idt->idt_outbufv, data_offset);
1772 1777 if (idb == NULL) {
1773 1778 mutex_exit(&idt->idt_mutex);
1774 1779 idm_task_rele(idt);
1775 1780 IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find buffer");
1776 1781 idm_pdu_rx_protocol_error(ic, pdu);
1777 1782 return;
1778 1783 }
1779 1784
1780 1785 /* return buffer contains this data */
1781 1786 if (data_offset + data_length > idb->idb_buflen) {
1782 1787 /* Overflow */
1783 1788 mutex_exit(&idt->idt_mutex);
1784 1789 idm_task_rele(idt);
1785 1790 IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: read from outside "
1786 1791 "buffer");
1787 1792 idm_pdu_rx_protocol_error(ic, pdu);
1788 1793 return;
1789 1794 }
1790 1795
1791 1796 idt->idt_r2t_ttt = rtt_hdr->ttt;
1792 1797 idt->idt_exp_datasn = 0;
1793 1798
1794 1799 idm_so_send_rtt_data(ic, idt, idb, data_offset,
1795 1800 ntohl(rtt_hdr->data_length));
1796 1801 /*
1797 1802 * the idt_mutex is released in idm_so_send_rtt_data
1798 1803 */
1799 1804
1800 1805 idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1801 1806 idm_task_rele(idt);
1802 1807
1803 1808 }
1804 1809
1805 1810 idm_status_t
1806 1811 idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu)
1807 1812 {
1808 1813 uint8_t pad[ISCSI_PAD_WORD_LEN];
1809 1814 int pad_len;
1810 1815 uint32_t data_digest_crc;
1811 1816 uint32_t crc_calculated;
1812 1817 int total_len;
1813 1818 idm_so_conn_t *so_conn;
1814 1819
1815 1820 so_conn = ic->ic_transport_private;
1816 1821
1817 1822 pad_len = ((ISCSI_PAD_WORD_LEN -
1818 1823 (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) &
1819 1824 (ISCSI_PAD_WORD_LEN - 1));
1820 1825
1821 1826 ASSERT(pdu->isp_iovlen < (PDU_MAX_IOVLEN - 2)); /* pad + data digest */
1822 1827
1823 1828 total_len = pdu->isp_datalen;
1824 1829
1825 1830 if (pad_len) {
1826 1831 pdu->isp_iov[pdu->isp_iovlen].iov_base = (char *)&pad;
1827 1832 pdu->isp_iov[pdu->isp_iovlen].iov_len = pad_len;
1828 1833 total_len += pad_len;
1829 1834 pdu->isp_iovlen++;
1830 1835 }
1831 1836
1832 1837 /* setup data digest */
1833 1838 if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) {
1834 1839 pdu->isp_iov[pdu->isp_iovlen].iov_base =
1835 1840 (char *)&data_digest_crc;
1836 1841 pdu->isp_iov[pdu->isp_iovlen].iov_len =
1837 1842 sizeof (data_digest_crc);
1838 1843 total_len += sizeof (data_digest_crc);
1839 1844 pdu->isp_iovlen++;
1840 1845 }
1841 1846
1842 1847 pdu->isp_data = (uint8_t *)(uintptr_t)pdu->isp_iov[0].iov_base;
1843 1848
1844 1849 if (idm_iov_sorecv(so_conn->ic_so, &pdu->isp_iov[0],
1845 1850 pdu->isp_iovlen, total_len) != 0) {
1846 1851 return (IDM_STATUS_IO);
1847 1852 }
1848 1853
1849 1854 if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) {
1850 1855 crc_calculated = idm_crc32c(pdu->isp_data,
1851 1856 pdu->isp_datalen);
1852 1857 if (pad_len) {
1853 1858 crc_calculated = idm_crc32c_continued((char *)&pad,
1854 1859 pad_len, crc_calculated);
1855 1860 }
1856 1861 if (crc_calculated != data_digest_crc) {
1857 1862 IDM_CONN_LOG(CE_WARN,
1858 1863 "idm_sorecvdata: "
1859 1864 "CRC error: actual 0x%x, calc 0x%x",
1860 1865 data_digest_crc, crc_calculated);
1861 1866
1862 1867 /* Invalid Data Digest */
1863 1868 return (IDM_STATUS_DATA_DIGEST);
1864 1869 }
1865 1870 }
1866 1871
1867 1872 return (IDM_STATUS_SUCCESS);
1868 1873 }
1869 1874
1870 1875 /*
1871 1876 * idm_sorecv_scsidata() is used to receive scsi data from the socket. The
1872 1877 * Data-type PDU header must be read into the idm_pdu_t structure prior to
1873 1878 * calling this function.
1874 1879 */
1875 1880 idm_status_t
1876 1881 idm_sorecv_scsidata(idm_conn_t *ic, idm_pdu_t *pdu)
1877 1882 {
1878 1883 iscsi_data_hdr_t *bhs;
1879 1884 idm_task_t *task;
1880 1885 uint32_t offset;
1881 1886 uint8_t opcode;
1882 1887 uint32_t dlength;
1883 1888 list_t *buflst;
1884 1889 uint32_t xfer_bytes;
1885 1890 idm_status_t status;
1886 1891
1887 1892 ASSERT(ic != NULL);
1888 1893 ASSERT(pdu != NULL);
1889 1894
1890 1895 bhs = (iscsi_data_hdr_t *)pdu->isp_hdr;
1891 1896
1892 1897 offset = ntohl(bhs->offset);
1893 1898 opcode = bhs->opcode;
1894 1899 dlength = n2h24(bhs->dlength);
1895 1900
1896 1901 ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) ||
1897 1902 (opcode == ISCSI_OP_SCSI_DATA));
1898 1903
1899 1904 /*
1900 1905 * Successful lookup implicitly gets a "hold" on the task. This
1901 1906 * hold must be released before leaving this function. At one
1902 1907 * point we were caching this task context and retaining the hold
1903 1908 * but it turned out to be very difficult to release the hold properly.
1904 1909 * The task can be aborted and the connection shutdown between this
1905 1910 * call and the subsequent expected call to idm_so_rx_datain/
1906 1911 * idm_so_rx_dataout (in which case those functions are not called).
1907 1912 * Releasing the hold in the PDU callback doesn't work well either
1908 1913 * because the whole task may be completed by then at which point
1909 1914 * it is too late to release the hold -- for better or worse this
1910 1915 * code doesn't wait on the refcnts during normal operation.
1911 1916 * idm_task_find() is very fast and it is not a huge burden if we
1912 1917 * have to do it twice.
1913 1918 */
1914 1919 task = idm_task_find(ic, bhs->itt, bhs->ttt);
1915 1920 if (task == NULL) {
1916 1921 IDM_CONN_LOG(CE_WARN,
1917 1922 "idm_sorecv_scsidata: could not find task");
1918 1923 return (IDM_STATUS_FAIL);
1919 1924 }
1920 1925
1921 1926 mutex_enter(&task->idt_mutex);
1922 1927 buflst = (opcode == ISCSI_OP_SCSI_DATA_RSP) ?
1923 1928 &task->idt_inbufv : &task->idt_outbufv;
1924 1929 pdu->isp_sorx_buf = idm_buf_find(buflst, offset);
1925 1930 mutex_exit(&task->idt_mutex);
1926 1931
1927 1932 if (pdu->isp_sorx_buf == NULL) {
1928 1933 idm_task_rele(task);
1929 1934 IDM_CONN_LOG(CE_WARN, "idm_sorecv_scsidata: could not find "
1930 1935 "buffer for offset %x opcode=%x",
1931 1936 offset, opcode);
1932 1937 return (IDM_STATUS_FAIL);
1933 1938 }
1934 1939
1935 1940 xfer_bytes = idm_fill_iov(pdu, pdu->isp_sorx_buf, offset, dlength);
1936 1941 ASSERT(xfer_bytes != 0);
1937 1942 if (xfer_bytes != dlength) {
1938 1943 idm_task_rele(task);
1939 1944 /*
1940 1945 * Buffer overflow, connection error. The PDU data is still
1941 1946 * sitting in the socket so we can't use the connection
1942 1947 * again until that data is drained.
1943 1948 */
1944 1949 return (IDM_STATUS_FAIL);
1945 1950 }
1946 1951
1947 1952 status = idm_sorecvdata(ic, pdu);
1948 1953
1949 1954 idm_task_rele(task);
1950 1955
1951 1956 return (status);
1952 1957 }
1953 1958
1954 1959 static uint32_t
1955 1960 idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb, uint32_t ro, uint32_t dlength)
1956 1961 {
1957 1962 uint32_t buf_ro = ro - idb->idb_bufoffset;
1958 1963 uint32_t xfer_len = min(dlength, idb->idb_buflen - buf_ro);
1959 1964
1960 1965 ASSERT(ro >= idb->idb_bufoffset);
1961 1966
1962 1967 pdu->isp_iov[pdu->isp_iovlen].iov_base =
1963 1968 (caddr_t)idb->idb_buf + buf_ro;
1964 1969 pdu->isp_iov[pdu->isp_iovlen].iov_len = xfer_len;
1965 1970 pdu->isp_iovlen++;
1966 1971
1967 1972 return (xfer_len);
1968 1973 }
1969 1974
1970 1975 int
1971 1976 idm_sorecv_nonscsidata(idm_conn_t *ic, idm_pdu_t *pdu)
1972 1977 {
1973 1978 pdu->isp_data = kmem_alloc(pdu->isp_datalen, KM_SLEEP);
1974 1979 ASSERT(pdu->isp_data != NULL);
1975 1980
1976 1981 pdu->isp_databuflen = pdu->isp_datalen;
1977 1982 pdu->isp_iov[0].iov_base = (caddr_t)pdu->isp_data;
1978 1983 pdu->isp_iov[0].iov_len = pdu->isp_datalen;
1979 1984 pdu->isp_iovlen = 1;
1980 1985 /*
1981 1986 * Since we are associating a new data buffer with this received
1982 1987 * PDU we need to set a specific callback to free the data
1983 1988 * after the PDU is processed.
1984 1989 */
1985 1990 pdu->isp_flags |= IDM_PDU_ADDL_DATA;
1986 1991 pdu->isp_callback = idm_sorx_addl_pdu_cb;
1987 1992
1988 1993 return (idm_sorecvdata(ic, pdu));
1989 1994 }
1990 1995
1991 1996 void
1992 1997 idm_sorx_thread(void *arg)
1993 1998 {
1994 1999 boolean_t conn_failure = B_FALSE;
1995 2000 idm_conn_t *ic = (idm_conn_t *)arg;
1996 2001 idm_so_conn_t *so_conn;
1997 2002 idm_pdu_t *pdu;
1998 2003 idm_status_t rc;
1999 2004
2000 2005 idm_conn_hold(ic);
2001 2006
2002 2007 mutex_enter(&ic->ic_mutex);
2003 2008
2004 2009 so_conn = ic->ic_transport_private;
2005 2010 so_conn->ic_rx_thread_running = B_TRUE;
2006 2011 so_conn->ic_rx_thread_did = so_conn->ic_rx_thread->t_did;
2007 2012 cv_signal(&ic->ic_cv);
2008 2013
2009 2014 while (so_conn->ic_rx_thread_running) {
2010 2015 mutex_exit(&ic->ic_mutex);
2011 2016
2012 2017 /*
2013 2018 * Get PDU with default header size (large enough for
2014 2019 * BHS plus any anticipated AHS). PDU from
2015 2020 * the cache will have all values set correctly
2016 2021 * for sockets RX including callback.
2017 2022 */
2018 2023 pdu = kmem_cache_alloc(idm.idm_sorx_pdu_cache, KM_SLEEP);
2019 2024 pdu->isp_ic = ic;
2020 2025 pdu->isp_flags = 0;
2021 2026 pdu->isp_transport_hdrlen = 0;
2022 2027
2023 2028 if ((rc = idm_sorecvhdr(ic, pdu)) != 0) {
2024 2029 /*
2025 2030 * Call idm_pdu_complete so that we call the callback
2026 2031 * and ensure any memory allocated in idm_sorecvhdr
2027 2032 * gets freed up.
2028 2033 */
2029 2034 idm_pdu_complete(pdu, IDM_STATUS_FAIL);
2030 2035
2031 2036 /*
2032 2037 * If ic_rx_thread_running is still set then
2033 2038 * this is some kind of connection problem
2034 2039 * on the socket. In this case we want to
2035 2040 * generate an event. Otherwise some other
2036 2041 * thread closed the socket due to another
2037 2042 * issue in which case we don't need to
2038 2043 * generate an event.
2039 2044 */
2040 2045 mutex_enter(&ic->ic_mutex);
2041 2046 if (so_conn->ic_rx_thread_running) {
2042 2047 conn_failure = B_TRUE;
2043 2048 so_conn->ic_rx_thread_running = B_FALSE;
2044 2049 }
2045 2050
2046 2051 continue;
2047 2052 }
2048 2053
2049 2054 /*
2050 2055 * Header has been read and validated. Now we need
2051 2056 * to read the PDU data payload (if present). SCSI data
2052 2057 * need to be transferred from the socket directly into
2053 2058 * the associated transfer buffer for the SCSI task.
2054 2059 */
2055 2060 if (pdu->isp_datalen != 0) {
2056 2061 if ((IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA) ||
2057 2062 (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP)) {
2058 2063 rc = idm_sorecv_scsidata(ic, pdu);
2059 2064 /*
2060 2065 * All SCSI errors are fatal to the
2061 2066 * connection right now since we have no
2062 2067 * place to put the data. What we need
2063 2068 * is some kind of sink to dispose of unwanted
2064 2069 * SCSI data. For example an invalid task tag
2065 2070 * should not kill the connection (although
2066 2071 * we may want to drop the connection).
2067 2072 */
2068 2073 } else {
2069 2074 /*
2070 2075 * Not data PDUs so allocate a buffer for the
2071 2076 * data segment and read the remaining data.
2072 2077 */
2073 2078 rc = idm_sorecv_nonscsidata(ic, pdu);
2074 2079 }
2075 2080 if (rc != 0) {
2076 2081 /*
2077 2082 * Call idm_pdu_complete so that we call the
2078 2083 * callback and ensure any memory allocated
2079 2084 * in idm_sorecvhdr gets freed up.
2080 2085 */
2081 2086 idm_pdu_complete(pdu, IDM_STATUS_FAIL);
2082 2087
2083 2088 /*
2084 2089 * If ic_rx_thread_running is still set then
2085 2090 * this is some kind of connection problem
2086 2091 * on the socket. In this case we want to
2087 2092 * generate an event. Otherwise some other
2088 2093 * thread closed the socket due to another
2089 2094 * issue in which case we don't need to
2090 2095 * generate an event.
2091 2096 */
2092 2097 mutex_enter(&ic->ic_mutex);
2093 2098 if (so_conn->ic_rx_thread_running) {
2094 2099 conn_failure = B_TRUE;
2095 2100 so_conn->ic_rx_thread_running = B_FALSE;
2096 2101 }
2097 2102 continue;
2098 2103 }
2099 2104 }
2100 2105
2101 2106 /*
2102 2107 * Process RX PDU
2103 2108 */
2104 2109 idm_pdu_rx(ic, pdu);
2105 2110
2106 2111 mutex_enter(&ic->ic_mutex);
2107 2112 }
2108 2113
2109 2114 mutex_exit(&ic->ic_mutex);
2110 2115
2111 2116 /*
2112 2117 * If we dropped out of the RX processing loop because of
2113 2118 * a socket problem or other connection failure (including
2114 2119 * digest errors) then we need to generate a state machine
2115 2120 * event to shut the connection down.
2116 2121 * If the state machine is already in, for example, INIT_ERROR, this
2117 2122 * event will get dropped, and the TX thread will never be notified
2118 2123 * to shut down. To be safe, we'll just notify it here.
2119 2124 */
2120 2125 if (conn_failure) {
2121 2126 if (so_conn->ic_tx_thread_running) {
2122 2127 so_conn->ic_tx_thread_running = B_FALSE;
2123 2128 mutex_enter(&so_conn->ic_tx_mutex);
2124 2129 cv_signal(&so_conn->ic_tx_cv);
2125 2130 mutex_exit(&so_conn->ic_tx_mutex);
2126 2131 }
2127 2132
2128 2133 idm_conn_event(ic, CE_TRANSPORT_FAIL, rc);
2129 2134 }
2130 2135
2131 2136 idm_conn_rele(ic);
2132 2137
2133 2138 thread_exit();
2134 2139 }
2135 2140
2136 2141 /*
2137 2142 * idm_so_tx
2138 2143 *
2139 2144 * This is the implementation of idm_transport_ops_t's it_tx_pdu entry
2140 2145 * point. By definition, it is supposed to be fast. So, simply queue
2141 2146 * the entry and return. The real work is done by idm_i_so_tx() via
2142 2147 * idm_sotx_thread().
2143 2148 */
2144 2149
2145 2150 static void
2146 2151 idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu)
2147 2152 {
2148 2153 idm_so_conn_t *so_conn = ic->ic_transport_private;
2149 2154
2150 2155 ASSERT(pdu->isp_ic == ic);
2151 2156 mutex_enter(&so_conn->ic_tx_mutex);
2152 2157
2153 2158 if (!so_conn->ic_tx_thread_running) {
2154 2159 mutex_exit(&so_conn->ic_tx_mutex);
2155 2160 idm_pdu_complete(pdu, IDM_STATUS_ABORTED);
2156 2161 return;
2157 2162 }
2158 2163
2159 2164 list_insert_tail(&so_conn->ic_tx_list, (void *)pdu);
2160 2165 cv_signal(&so_conn->ic_tx_cv);
2161 2166 mutex_exit(&so_conn->ic_tx_mutex);
2162 2167 }
2163 2168
2164 2169 static idm_status_t
2165 2170 idm_i_so_tx(idm_pdu_t *pdu)
2166 2171 {
2167 2172 idm_conn_t *ic = pdu->isp_ic;
2168 2173 idm_status_t status = IDM_STATUS_SUCCESS;
2169 2174 uint8_t pad[ISCSI_PAD_WORD_LEN];
2170 2175 int pad_len;
2171 2176 uint32_t hdr_digest_crc;
2172 2177 uint32_t data_digest_crc = 0;
2173 2178 int total_len = 0;
2174 2179 int iovlen = 0;
2175 2180 struct iovec iov[6];
2176 2181 idm_so_conn_t *so_conn;
2177 2182
2178 2183 so_conn = ic->ic_transport_private;
2179 2184
2180 2185 /* Setup BHS */
2181 2186 iov[iovlen].iov_base = (caddr_t)pdu->isp_hdr;
2182 2187 iov[iovlen].iov_len = pdu->isp_hdrlen;
2183 2188 total_len += iov[iovlen].iov_len;
2184 2189 iovlen++;
2185 2190
2186 2191 /* Setup header digest */
2187 2192 if (((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) &&
2188 2193 (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST)) {
2189 2194 hdr_digest_crc = idm_crc32c(pdu->isp_hdr, pdu->isp_hdrlen);
2190 2195
2191 2196 iov[iovlen].iov_base = (caddr_t)&hdr_digest_crc;
2192 2197 iov[iovlen].iov_len = sizeof (hdr_digest_crc);
2193 2198 total_len += iov[iovlen].iov_len;
2194 2199 iovlen++;
2195 2200 }
2196 2201
2197 2202 /* Setup the data */
2198 2203 if (pdu->isp_datalen) {
2199 2204 idm_task_t *idt;
2200 2205 idm_buf_t *idb;
2201 2206 iscsi_data_hdr_t *ihp;
2202 2207 ihp = (iscsi_data_hdr_t *)pdu->isp_hdr;
2203 2208 /* Write of immediate data */
2204 2209 if (ic->ic_ffp &&
2205 2210 (ihp->opcode == ISCSI_OP_SCSI_CMD ||
2206 2211 ihp->opcode == ISCSI_OP_SCSI_DATA)) {
2207 2212 idt = idm_task_find(ic, ihp->itt, ihp->ttt);
2208 2213 if (idt) {
2209 2214 mutex_enter(&idt->idt_mutex);
2210 2215 idb = idm_buf_find(&idt->idt_outbufv, 0);
2211 2216 mutex_exit(&idt->idt_mutex);
2212 2217 /*
2213 2218 * If the initiator call to idm_buf_alloc
2214 2219 * failed then we can get to this point
2215 2220 * without a bound buffer. The associated
2216 2221 * connection failure will clean things up
2217 2222 * later. It would be nice to come up with
2218 2223 * a cleaner way to handle this. In
2219 2224 * particular it seems absurd to look up
2220 2225 * the task and the buffer just to update
2221 2226 * this counter.
2222 2227 */
2223 2228 if (idb)
2224 2229 idb->idb_xfer_len += pdu->isp_datalen;
2225 2230 idm_task_rele(idt);
2226 2231 }
2227 2232 }
2228 2233
2229 2234 iov[iovlen].iov_base = (caddr_t)pdu->isp_data;
2230 2235 iov[iovlen].iov_len = pdu->isp_datalen;
2231 2236 total_len += iov[iovlen].iov_len;
2232 2237 iovlen++;
2233 2238 }
2234 2239
2235 2240 /* Setup the data pad if necessary */
2236 2241 pad_len = ((ISCSI_PAD_WORD_LEN -
2237 2242 (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) &
2238 2243 (ISCSI_PAD_WORD_LEN - 1));
2239 2244
2240 2245 if (pad_len) {
2241 2246 bzero(pad, sizeof (pad));
2242 2247 iov[iovlen].iov_base = (void *)&pad;
2243 2248 iov[iovlen].iov_len = pad_len;
2244 2249 total_len += iov[iovlen].iov_len;
2245 2250 iovlen++;
2246 2251 }
2247 2252
2248 2253 /*
2249 2254 * Setup the data digest if enabled. Data-digest is not sent
2250 2255 * for login-phase PDUs.
2251 2256 */
2252 2257 if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) &&
2253 2258 ((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) &&
2254 2259 (pdu->isp_datalen || pad_len)) {
2255 2260 /*
2256 2261 * RFC3720/10.2.3: A zero-length Data Segment also
2257 2262 * implies a zero-length data digest.
2258 2263 */
2259 2264 if (pdu->isp_datalen) {
2260 2265 data_digest_crc = idm_crc32c(pdu->isp_data,
2261 2266 pdu->isp_datalen);
2262 2267 }
2263 2268 if (pad_len) {
2264 2269 data_digest_crc = idm_crc32c_continued(&pad,
2265 2270 pad_len, data_digest_crc);
2266 2271 }
2267 2272
2268 2273 iov[iovlen].iov_base = (caddr_t)&data_digest_crc;
2269 2274 iov[iovlen].iov_len = sizeof (data_digest_crc);
2270 2275 total_len += iov[iovlen].iov_len;
2271 2276 iovlen++;
2272 2277 }
2273 2278
2274 2279 /* Transmit the PDU */
2275 2280 if (idm_iov_sosend(so_conn->ic_so, &iov[0], iovlen,
2276 2281 total_len) != 0) {
2277 2282 /* Set error status */
2278 2283 IDM_CONN_LOG(CE_WARN,
2279 2284 "idm_so_tx: failed to transmit the PDU, so: %p ic: %p "
2280 2285 "data: %p", (void *) so_conn->ic_so, (void *) ic,
2281 2286 (void *) pdu->isp_data);
2282 2287 status = IDM_STATUS_IO;
2283 2288 }
2284 2289
2285 2290 /*
2286 2291 * Success does not mean that the PDU actually reached the
2287 2292 * remote node since it could get dropped along the way.
2288 2293 */
2289 2294 idm_pdu_complete(pdu, status);
2290 2295
2291 2296 return (status);
2292 2297 }
2293 2298
2294 2299 /*
2295 2300 * The idm_so_buf_tx_to_ini() is used by the target iSCSI layer to transmit the
2296 2301 * Data-In PDUs using sockets. Based on the negotiated MaxRecvDataSegmentLength,
2297 2302 * the buffer is segmented into a sequence of Data-In PDUs, ordered by DataSN.
2298 2303 * A target can invoke this function multiple times for a single read command
2299 2304 * (identified by the same ITT) to split the input into several sequences.
2300 2305 *
2301 2306 * DataSN starts with 0 for the first data PDU of an input command and advances
2302 2307 * by 1 for each subsequent data PDU. Each sequence will have its own F bit,
2303 2308 * which is set to 1 for the last data PDU of a sequence.
2304 2309 * If the initiator supports phase collapse, the status bit must be set along
2305 2310 * with the F bit to indicate that the status is shipped together with the last
2306 2311 * Data-In PDU.
2307 2312 *
2308 2313 * The data PDUs within a sequence will be sent in order with the buffer offset
2309 2314 * in increasing order. i.e. initiator and target must have negotiated the
2310 2315 * "DataPDUInOrder" to "Yes". The order between sequences is not enforced.
2311 2316 *
2312 2317 * Caller holds idt->idt_mutex
2313 2318 */
2314 2319 static idm_status_t
2315 2320 idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb)
2316 2321 {
2317 2322 idm_so_conn_t *so_conn = idb->idb_ic->ic_transport_private;
2318 2323 idm_pdu_t tmppdu;
2319 2324
2320 2325 ASSERT(mutex_owned(&idt->idt_mutex));
2321 2326
2322 2327 /*
2323 2328 * Put the idm_buf_t on the tx queue. It will be transmitted by
2324 2329 * idm_sotx_thread.
2325 2330 */
2326 2331 mutex_enter(&so_conn->ic_tx_mutex);
2327 2332
2328 2333 DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
2329 2334 uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2330 2335 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2331 2336 uint32_t, idb->idb_xfer_len, int, XFER_BUF_TX_TO_INI);
2332 2337
2333 2338 if (!so_conn->ic_tx_thread_running) {
2334 2339 mutex_exit(&so_conn->ic_tx_mutex);
2335 2340 /*
2336 2341 * Don't release idt->idt_mutex since we're supposed to hold
2337 2342 * in when calling idm_buf_tx_to_ini_done
2338 2343 */
2339 2344 DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
2340 2345 uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2341 2346 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2342 2347 uint32_t, idb->idb_xfer_len,
2343 2348 int, XFER_BUF_TX_TO_INI);
2344 2349 idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED);
2345 2350 return (IDM_STATUS_FAIL);
2346 2351 }
2347 2352
2348 2353 /*
2349 2354 * Build a template for the data PDU headers we will use so that
2350 2355 * the SN values will stay consistent with other PDU's we are
2351 2356 * transmitting like R2T and SCSI status.
2352 2357 */
2353 2358 bzero(&idb->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t));
2354 2359 tmppdu.isp_hdr = &idb->idb_data_hdr_tmpl;
2355 2360 (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu,
2356 2361 ISCSI_OP_SCSI_DATA_RSP);
2357 2362 idb->idb_tx_thread = B_TRUE;
2358 2363 list_insert_tail(&so_conn->ic_tx_list, (void *)idb);
2359 2364 cv_signal(&so_conn->ic_tx_cv);
2360 2365 mutex_exit(&so_conn->ic_tx_mutex);
2361 2366 mutex_exit(&idt->idt_mutex);
2362 2367
2363 2368 /*
2364 2369 * Returning success here indicates the transfer was successfully
2365 2370 * dispatched -- it does not mean that the transfer completed
2366 2371 * successfully.
2367 2372 */
2368 2373 return (IDM_STATUS_SUCCESS);
2369 2374 }
2370 2375
2371 2376 /*
2372 2377 * The idm_so_buf_rx_from_ini() is used by the target iSCSI layer to specify the
2373 2378 * data blocks it is ready to receive from the initiator in response to a WRITE
2374 2379 * SCSI command. The target iSCSI layer passes the information about the desired
2375 2380 * data blocks to the initiator in one R2T PDU. The receiving buffer, the buffer
2376 2381 * offset and datalen are passed via the 'idb' argument.
2377 2382 *
2378 2383 * Scope for Prototype build:
2379 2384 * R2Ts are required for any Data-Out PDU, i.e. initiator and target must have
2380 2385 * negotiated the "InitialR2T" to "Yes".
2381 2386 *
2382 2387 * Caller holds idt->idt_mutex
2383 2388 */
2384 2389 static idm_status_t
2385 2390 idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb)
2386 2391 {
2387 2392 idm_pdu_t *pdu;
2388 2393 iscsi_rtt_hdr_t *rtt;
2389 2394
2390 2395 ASSERT(mutex_owned(&idt->idt_mutex));
2391 2396
2392 2397 DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
2393 2398 uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2394 2399 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2395 2400 uint32_t, idb->idb_xfer_len, int, XFER_BUF_RX_FROM_INI);
2396 2401
2397 2402 pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP);
2398 2403 pdu->isp_ic = idt->idt_ic;
2399 2404 pdu->isp_flags = IDM_PDU_SET_STATSN;
2400 2405 bzero(pdu->isp_hdr, sizeof (iscsi_rtt_hdr_t));
2401 2406
2402 2407 /* iSCSI layer fills the TTT, ITT, ExpCmdSN, MaxCmdSN */
2403 2408 (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, pdu, ISCSI_OP_RTT_RSP);
2404 2409
2405 2410 /* set the rttsn, rtt.flags, rtt.data_offset and rtt.data_length */
2406 2411 rtt = (iscsi_rtt_hdr_t *)(pdu->isp_hdr);
2407 2412
2408 2413 rtt->opcode = ISCSI_OP_RTT_RSP;
2409 2414 rtt->flags = ISCSI_FLAG_FINAL;
2410 2415 rtt->data_offset = htonl(idb->idb_bufoffset);
2411 2416 rtt->data_length = htonl(idb->idb_xfer_len);
2412 2417 rtt->rttsn = htonl(idt->idt_exp_rttsn++);
2413 2418
2414 2419 /* Keep track of buffer offsets */
2415 2420 idb->idb_exp_offset = idb->idb_bufoffset;
2416 2421 mutex_exit(&idt->idt_mutex);
2417 2422
2418 2423 /*
2419 2424 * Transmit the PDU.
2420 2425 */
2421 2426 idm_pdu_tx(pdu);
2422 2427
2423 2428 return (IDM_STATUS_SUCCESS);
2424 2429 }
2425 2430
2426 2431 static idm_status_t
2427 2432 idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen)
2428 2433 {
2429 2434 if ((buflen > IDM_SO_BUF_CACHE_LB) && (buflen <= IDM_SO_BUF_CACHE_UB)) {
2430 2435 idb->idb_buf = kmem_cache_alloc(idm.idm_so_128k_buf_cache,
2431 2436 KM_NOSLEEP);
2432 2437 idb->idb_buf_private = idm.idm_so_128k_buf_cache;
2433 2438 } else {
2434 2439 idb->idb_buf = kmem_alloc(buflen, KM_NOSLEEP);
2435 2440 idb->idb_buf_private = NULL;
2436 2441 }
2437 2442
2438 2443 if (idb->idb_buf == NULL) {
2439 2444 IDM_CONN_LOG(CE_NOTE,
2440 2445 "idm_so_buf_alloc: failed buffer allocation");
2441 2446 return (IDM_STATUS_FAIL);
2442 2447 }
2443 2448
2444 2449 return (IDM_STATUS_SUCCESS);
2445 2450 }
2446 2451
2447 2452 /* ARGSUSED */
2448 2453 static idm_status_t
2449 2454 idm_so_buf_setup(idm_buf_t *idb)
2450 2455 {
2451 2456 /* Ensure bufalloc'd flag is unset */
2452 2457 idb->idb_bufalloc = B_FALSE;
2453 2458
2454 2459 return (IDM_STATUS_SUCCESS);
2455 2460 }
2456 2461
2457 2462 /* ARGSUSED */
2458 2463 static void
2459 2464 idm_so_buf_teardown(idm_buf_t *idb)
2460 2465 {
2461 2466 /* nothing to do here */
2462 2467 }
2463 2468
2464 2469 static void
2465 2470 idm_so_buf_free(idm_buf_t *idb)
2466 2471 {
2467 2472 if (idb->idb_buf_private == NULL) {
2468 2473 kmem_free(idb->idb_buf, idb->idb_buflen);
2469 2474 } else {
2470 2475 kmem_cache_free(idb->idb_buf_private, idb->idb_buf);
2471 2476 }
2472 2477 }
2473 2478
2474 2479 static void
2475 2480 idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt, idm_buf_t *idb,
2476 2481 uint32_t offset, uint32_t length)
2477 2482 {
2478 2483 idm_so_conn_t *so_conn = ic->ic_transport_private;
2479 2484 idm_pdu_t tmppdu;
2480 2485 idm_buf_t *rtt_buf;
2481 2486
2482 2487 ASSERT(mutex_owned(&idt->idt_mutex));
2483 2488
2484 2489 /*
2485 2490 * Allocate a buffer to represent the RTT transfer. We could further
2486 2491 * optimize this by allocating the buffers internally from an rtt
2487 2492 * specific buffer cache since this is socket-specific code but for
2488 2493 * now we will keep it simple.
2489 2494 */
2490 2495 rtt_buf = idm_buf_alloc(ic, (uint8_t *)idb->idb_buf + offset, length);
2491 2496 if (rtt_buf == NULL) {
2492 2497 /*
2493 2498 * If we're in FFP then the failure was likely a resource
2494 2499 * allocation issue and we should close the connection by
2495 2500 * sending a CE_TRANSPORT_FAIL event.
2496 2501 *
2497 2502 * If we're not in FFP then idm_buf_alloc will always
2498 2503 * fail and the state is transitioning to "complete" anyway
2499 2504 * so we won't bother to send an event.
2500 2505 */
2501 2506 mutex_enter(&ic->ic_state_mutex);
2502 2507 if (ic->ic_ffp)
2503 2508 idm_conn_event_locked(ic, CE_TRANSPORT_FAIL,
2504 2509 NULL, CT_NONE);
2505 2510 mutex_exit(&ic->ic_state_mutex);
2506 2511 mutex_exit(&idt->idt_mutex);
2507 2512 return;
2508 2513 }
2509 2514
2510 2515 rtt_buf->idb_buf_cb = NULL;
2511 2516 rtt_buf->idb_cb_arg = NULL;
2512 2517 rtt_buf->idb_bufoffset = offset;
2513 2518 rtt_buf->idb_xfer_len = length;
2514 2519 rtt_buf->idb_ic = idt->idt_ic;
2515 2520 rtt_buf->idb_task_binding = idt;
2516 2521
2517 2522 /*
2518 2523 * The new buffer (if any) represents an additional
2519 2524 * reference on the task
2520 2525 */
2521 2526 idm_task_hold(idt);
2522 2527 mutex_exit(&idt->idt_mutex);
2523 2528
2524 2529 /*
2525 2530 * Put the idm_buf_t on the tx queue. It will be transmitted by
2526 2531 * idm_sotx_thread.
2527 2532 */
2528 2533 mutex_enter(&so_conn->ic_tx_mutex);
2529 2534
2530 2535 if (!so_conn->ic_tx_thread_running) {
2531 2536 idm_buf_free(rtt_buf);
2532 2537 mutex_exit(&so_conn->ic_tx_mutex);
2533 2538 idm_task_rele(idt);
2534 2539 return;
2535 2540 }
2536 2541
2537 2542 /*
2538 2543 * Build a template for the data PDU headers we will use so that
2539 2544 * the SN values will stay consistent with other PDU's we are
2540 2545 * transmitting like R2T and SCSI status.
2541 2546 */
2542 2547 bzero(&rtt_buf->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t));
2543 2548 tmppdu.isp_hdr = &rtt_buf->idb_data_hdr_tmpl;
2544 2549 (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu,
2545 2550 ISCSI_OP_SCSI_DATA);
2546 2551 rtt_buf->idb_tx_thread = B_TRUE;
2547 2552 rtt_buf->idb_in_transport = B_TRUE;
2548 2553 list_insert_tail(&so_conn->ic_tx_list, (void *)rtt_buf);
2549 2554 cv_signal(&so_conn->ic_tx_cv);
2550 2555 mutex_exit(&so_conn->ic_tx_mutex);
2551 2556 }
2552 2557
2553 2558 static void
2554 2559 idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb)
2555 2560 {
2556 2561 /*
2557 2562 * Don't worry about status -- we assume any error handling
2558 2563 * is performed by the caller (idm_sotx_thread).
2559 2564 */
2560 2565 idb->idb_in_transport = B_FALSE;
2561 2566 idm_task_rele(idt);
2562 2567 idm_buf_free(idb);
2563 2568 }
2564 2569
2565 2570 static idm_status_t
2566 2571 idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb,
2567 2572 uint32_t buf_region_offset, uint32_t buf_region_length)
2568 2573 {
2569 2574 idm_conn_t *ic;
2570 2575 uint32_t max_dataseglen;
2571 2576 size_t remainder, chunk;
2572 2577 uint32_t data_offset = buf_region_offset;
2573 2578 iscsi_data_hdr_t *bhs;
2574 2579 idm_pdu_t *pdu;
2575 2580 idm_status_t tx_status;
2576 2581
2577 2582 ASSERT(mutex_owned(&idt->idt_mutex));
2578 2583
2579 2584 ic = idt->idt_ic;
2580 2585
2581 2586 max_dataseglen = ic->ic_conn_params.max_xmit_dataseglen;
2582 2587 remainder = buf_region_length;
2583 2588
2584 2589 while (remainder) {
2585 2590 if (idt->idt_state != TASK_ACTIVE) {
2586 2591 ASSERT((idt->idt_state != TASK_IDLE) &&
2587 2592 (idt->idt_state != TASK_COMPLETE));
2588 2593 return (IDM_STATUS_ABORTED);
2589 2594 }
2590 2595
2591 2596 /* check to see if we need to chunk the data */
2592 2597 if (remainder > max_dataseglen) {
2593 2598 chunk = max_dataseglen;
2594 2599 } else {
2595 2600 chunk = remainder;
2596 2601 }
2597 2602
2598 2603 /* Data PDU headers will always be sizeof (iscsi_hdr_t) */
2599 2604 pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP);
2600 2605 pdu->isp_ic = ic;
2601 2606 pdu->isp_flags = 0; /* initialize isp_flags */
2602 2607
2603 2608 /*
2604 2609 * We've already built a build a header template
2605 2610 * to use during the transfer. Use this template so that
2606 2611 * the SN values stay consistent with any unrelated PDU's
2607 2612 * being transmitted.
2608 2613 */
2609 2614 bcopy(&idb->idb_data_hdr_tmpl, pdu->isp_hdr,
2610 2615 sizeof (iscsi_hdr_t));
2611 2616
2612 2617 /*
2613 2618 * Set DataSN, data offset, and flags in BHS
2614 2619 * For the prototype build, A = 0, S = 0, U = 0
2615 2620 */
2616 2621 bhs = (iscsi_data_hdr_t *)(pdu->isp_hdr);
2617 2622
2618 2623 bhs->datasn = htonl(idt->idt_exp_datasn++);
2619 2624
2620 2625 hton24(bhs->dlength, chunk);
2621 2626 bhs->offset = htonl(idb->idb_bufoffset + data_offset);
2622 2627
2623 2628 /* setup data */
2624 2629 pdu->isp_data = (uint8_t *)idb->idb_buf + data_offset;
2625 2630 pdu->isp_datalen = (uint_t)chunk;
2626 2631
2627 2632 if (chunk == remainder) {
2628 2633 bhs->flags = ISCSI_FLAG_FINAL; /* F bit set to 1 */
2629 2634 /* Piggyback the status with the last data PDU */
2630 2635 if (idt->idt_flags & IDM_TASK_PHASECOLLAPSE_REQ) {
2631 2636 pdu->isp_flags |= IDM_PDU_SET_STATSN |
2632 2637 IDM_PDU_ADVANCE_STATSN;
2633 2638 (*idt->idt_ic->ic_conn_ops.icb_update_statsn)
2634 2639 (idt, pdu);
2635 2640 idt->idt_flags |=
2636 2641 IDM_TASK_PHASECOLLAPSE_SUCCESS;
2637 2642
2638 2643 }
2639 2644 }
2640 2645
2641 2646 remainder -= chunk;
2642 2647 data_offset += chunk;
2643 2648
2644 2649 /* Instrument the data-send DTrace probe. */
2645 2650 if (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP) {
2646 2651 DTRACE_ISCSI_2(data__send,
2647 2652 idm_conn_t *, idt->idt_ic,
2648 2653 iscsi_data_rsp_hdr_t *,
2649 2654 (iscsi_data_rsp_hdr_t *)pdu->isp_hdr);
2650 2655 }
2651 2656
2652 2657 /*
2653 2658 * Now that we're done working with idt_exp_datasn,
2654 2659 * idt->idt_state and idb->idb_bufoffset we can release
2655 2660 * the task lock -- don't want to hold it across the
2656 2661 * call to idm_i_so_tx since we could block.
2657 2662 */
2658 2663 mutex_exit(&idt->idt_mutex);
2659 2664
2660 2665 /*
2661 2666 * Transmit the PDU. Call the internal routine directly
2662 2667 * as there is already implicit ordering.
2663 2668 */
2664 2669 if ((tx_status = idm_i_so_tx(pdu)) != IDM_STATUS_SUCCESS) {
2665 2670 mutex_enter(&idt->idt_mutex);
2666 2671 return (tx_status);
2667 2672 }
2668 2673
2669 2674 mutex_enter(&idt->idt_mutex);
2670 2675 idt->idt_tx_bytes += chunk;
2671 2676 }
2672 2677
2673 2678 return (IDM_STATUS_SUCCESS);
2674 2679 }
2675 2680
2676 2681 /*
2677 2682 * TX PDU cache
2678 2683 */
2679 2684 /* ARGSUSED */
2680 2685 int
2681 2686 idm_sotx_pdu_constructor(void *hdl, void *arg, int flags)
2682 2687 {
2683 2688 idm_pdu_t *pdu = hdl;
2684 2689
2685 2690 bzero(pdu, sizeof (idm_pdu_t));
2686 2691 pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */
2687 2692 pdu->isp_hdrlen = sizeof (iscsi_hdr_t);
2688 2693 pdu->isp_callback = idm_sotx_cache_pdu_cb;
2689 2694 pdu->isp_magic = IDM_PDU_MAGIC;
2690 2695 bzero(pdu->isp_hdr, sizeof (iscsi_hdr_t));
2691 2696
2692 2697 return (0);
2693 2698 }
2694 2699
2695 2700 /* ARGSUSED */
2696 2701 void
2697 2702 idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2698 2703 {
2699 2704 /* reset values between use */
2700 2705 pdu->isp_datalen = 0;
2701 2706
2702 2707 kmem_cache_free(idm.idm_sotx_pdu_cache, pdu);
2703 2708 }
2704 2709
2705 2710 /*
2706 2711 * RX PDU cache
2707 2712 */
2708 2713 /* ARGSUSED */
2709 2714 int
2710 2715 idm_sorx_pdu_constructor(void *hdl, void *arg, int flags)
2711 2716 {
2712 2717 idm_pdu_t *pdu = hdl;
2713 2718
2714 2719 bzero(pdu, sizeof (idm_pdu_t));
2715 2720 pdu->isp_magic = IDM_PDU_MAGIC;
2716 2721 pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */
2717 2722 pdu->isp_callback = idm_sorx_cache_pdu_cb;
2718 2723
2719 2724 return (0);
2720 2725 }
2721 2726
2722 2727 /* ARGSUSED */
2723 2728 static void
2724 2729 idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2725 2730 {
2726 2731 pdu->isp_iovlen = 0;
2727 2732 pdu->isp_sorx_buf = 0;
2728 2733 kmem_cache_free(idm.idm_sorx_pdu_cache, pdu);
2729 2734 }
2730 2735
2731 2736 static void
2732 2737 idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2733 2738 {
2734 2739 /*
2735 2740 * We had to modify our cached RX PDU with a longer header buffer
2736 2741 * and/or a longer data buffer. Release the new buffers and fix
2737 2742 * the fields back to what we would expect for a cached RX PDU.
2738 2743 */
2739 2744 if (pdu->isp_flags & IDM_PDU_ADDL_HDR) {
2740 2745 kmem_free(pdu->isp_hdr, pdu->isp_hdrlen);
2741 2746 }
2742 2747 if (pdu->isp_flags & IDM_PDU_ADDL_DATA) {
2743 2748 kmem_free(pdu->isp_data, pdu->isp_datalen);
2744 2749 }
2745 2750 pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1);
2746 2751 pdu->isp_hdrlen = sizeof (iscsi_hdr_t);
2747 2752 pdu->isp_data = NULL;
2748 2753 pdu->isp_datalen = 0;
2749 2754 pdu->isp_sorx_buf = 0;
2750 2755 pdu->isp_callback = idm_sorx_cache_pdu_cb;
2751 2756 idm_sorx_cache_pdu_cb(pdu, status);
2752 2757 }
2753 2758
2754 2759 /*
2755 2760 * This thread is only active when I/O is queued for transmit
2756 2761 * because the socket is busy.
2757 2762 */
2758 2763 void
2759 2764 idm_sotx_thread(void *arg)
2760 2765 {
2761 2766 idm_conn_t *ic = arg;
2762 2767 idm_tx_obj_t *object, *next;
2763 2768 idm_so_conn_t *so_conn;
2764 2769 idm_status_t status = IDM_STATUS_SUCCESS;
2765 2770
2766 2771 idm_conn_hold(ic);
2767 2772
2768 2773 mutex_enter(&ic->ic_mutex);
2769 2774 so_conn = ic->ic_transport_private;
2770 2775 so_conn->ic_tx_thread_running = B_TRUE;
2771 2776 so_conn->ic_tx_thread_did = so_conn->ic_tx_thread->t_did;
2772 2777 cv_signal(&ic->ic_cv);
2773 2778 mutex_exit(&ic->ic_mutex);
2774 2779
2775 2780 mutex_enter(&so_conn->ic_tx_mutex);
2776 2781
2777 2782 while (so_conn->ic_tx_thread_running) {
2778 2783 while (list_is_empty(&so_conn->ic_tx_list)) {
2779 2784 DTRACE_PROBE1(soconn__tx__sleep, idm_conn_t *, ic);
2780 2785 cv_wait(&so_conn->ic_tx_cv, &so_conn->ic_tx_mutex);
2781 2786 DTRACE_PROBE1(soconn__tx__wakeup, idm_conn_t *, ic);
2782 2787
2783 2788 if (!so_conn->ic_tx_thread_running) {
2784 2789 goto tx_bail;
2785 2790 }
2786 2791 }
2787 2792
2788 2793 object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list);
2789 2794 list_remove(&so_conn->ic_tx_list, object);
2790 2795 mutex_exit(&so_conn->ic_tx_mutex);
2791 2796
2792 2797 switch (object->idm_tx_obj_magic) {
2793 2798 case IDM_PDU_MAGIC: {
2794 2799 idm_pdu_t *pdu = (idm_pdu_t *)object;
2795 2800 DTRACE_PROBE2(soconn__tx__pdu, idm_conn_t *, ic,
2796 2801 idm_pdu_t *, (idm_pdu_t *)object);
2797 2802
2798 2803 if (pdu->isp_flags & IDM_PDU_SET_STATSN) {
2799 2804 /* No IDM task */
2800 2805 (ic->ic_conn_ops.icb_update_statsn)(NULL, pdu);
2801 2806 }
2802 2807 status = idm_i_so_tx((idm_pdu_t *)object);
2803 2808 break;
2804 2809 }
2805 2810 case IDM_BUF_MAGIC: {
2806 2811 idm_buf_t *idb = (idm_buf_t *)object;
2807 2812 idm_task_t *idt = idb->idb_task_binding;
2808 2813
2809 2814 DTRACE_PROBE2(soconn__tx__buf, idm_conn_t *, ic,
2810 2815 idm_buf_t *, idb);
2811 2816
2812 2817 mutex_enter(&idt->idt_mutex);
2813 2818 status = idm_so_send_buf_region(idt,
2814 2819 idb, 0, idb->idb_xfer_len);
2815 2820
2816 2821 /*
2817 2822 * TX thread owns the buffer so we expect it to
2818 2823 * be "in transport"
2819 2824 */
2820 2825 ASSERT(idb->idb_in_transport);
2821 2826 if (IDM_CONN_ISTGT(ic)) {
2822 2827 /*
2823 2828 * idm_buf_tx_to_ini_done releases
2824 2829 * idt->idt_mutex
2825 2830 */
2826 2831 DTRACE_ISCSI_8(xfer__done,
2827 2832 idm_conn_t *, idt->idt_ic,
2828 2833 uintptr_t, idb->idb_buf,
2829 2834 uint32_t, idb->idb_bufoffset,
2830 2835 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2831 2836 uint32_t, idb->idb_xfer_len,
2832 2837 int, XFER_BUF_TX_TO_INI);
2833 2838 idm_buf_tx_to_ini_done(idt, idb, status);
2834 2839 } else {
2835 2840 idm_so_send_rtt_data_done(idt, idb);
2836 2841 mutex_exit(&idt->idt_mutex);
2837 2842 }
2838 2843 break;
2839 2844 }
2840 2845
2841 2846 default:
2842 2847 IDM_CONN_LOG(CE_WARN, "idm_sotx_thread: Unknown magic "
2843 2848 "(0x%08x)", object->idm_tx_obj_magic);
2844 2849 status = IDM_STATUS_FAIL;
2845 2850 }
2846 2851
2847 2852 mutex_enter(&so_conn->ic_tx_mutex);
2848 2853
2849 2854 if (status != IDM_STATUS_SUCCESS) {
2850 2855 so_conn->ic_tx_thread_running = B_FALSE;
2851 2856 idm_conn_event(ic, CE_TRANSPORT_FAIL, status);
2852 2857 }
2853 2858 }
2854 2859
2855 2860 /*
2856 2861 * Before we leave, we need to abort every item remaining in the
2857 2862 * TX list.
2858 2863 */
2859 2864
2860 2865 tx_bail:
2861 2866 object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list);
2862 2867
2863 2868 while (object != NULL) {
2864 2869 next = list_next(&so_conn->ic_tx_list, object);
2865 2870
2866 2871 list_remove(&so_conn->ic_tx_list, object);
2867 2872 switch (object->idm_tx_obj_magic) {
2868 2873 case IDM_PDU_MAGIC:
2869 2874 idm_pdu_complete((idm_pdu_t *)object,
2870 2875 IDM_STATUS_ABORTED);
2871 2876 break;
2872 2877
2873 2878 case IDM_BUF_MAGIC: {
2874 2879 idm_buf_t *idb = (idm_buf_t *)object;
2875 2880 idm_task_t *idt = idb->idb_task_binding;
2876 2881 mutex_exit(&so_conn->ic_tx_mutex);
2877 2882 mutex_enter(&idt->idt_mutex);
2878 2883 /*
2879 2884 * TX thread owns the buffer so we expect it to
2880 2885 * be "in transport"
2881 2886 */
2882 2887 ASSERT(idb->idb_in_transport);
2883 2888 if (IDM_CONN_ISTGT(ic)) {
2884 2889 /*
2885 2890 * idm_buf_tx_to_ini_done releases
2886 2891 * idt->idt_mutex
2887 2892 */
2888 2893 DTRACE_ISCSI_8(xfer__done,
2889 2894 idm_conn_t *, idt->idt_ic,
2890 2895 uintptr_t, idb->idb_buf,
2891 2896 uint32_t, idb->idb_bufoffset,
2892 2897 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2893 2898 uint32_t, idb->idb_xfer_len,
2894 2899 int, XFER_BUF_TX_TO_INI);
2895 2900 idm_buf_tx_to_ini_done(idt, idb,
2896 2901 IDM_STATUS_ABORTED);
2897 2902 } else {
2898 2903 idm_so_send_rtt_data_done(idt, idb);
2899 2904 mutex_exit(&idt->idt_mutex);
2900 2905 }
2901 2906 mutex_enter(&so_conn->ic_tx_mutex);
2902 2907 break;
2903 2908 }
2904 2909 default:
2905 2910 IDM_CONN_LOG(CE_WARN,
2906 2911 "idm_sotx_thread: Unexpected magic "
2907 2912 "(0x%08x)", object->idm_tx_obj_magic);
2908 2913 }
2909 2914
2910 2915 object = next;
2911 2916 }
2912 2917
2913 2918 mutex_exit(&so_conn->ic_tx_mutex);
2914 2919 idm_conn_rele(ic);
2915 2920 thread_exit();
2916 2921 /*NOTREACHED*/
2917 2922 }
2918 2923
2919 2924 static void
2920 2925 idm_so_socket_set_nonblock(struct sonode *node)
2921 2926 {
2922 2927 (void) VOP_SETFL(node->so_vnode, node->so_flag,
2923 2928 (node->so_state | FNONBLOCK), CRED(), NULL);
2924 2929 }
2925 2930
2926 2931 static void
2927 2932 idm_so_socket_set_block(struct sonode *node)
2928 2933 {
2929 2934 (void) VOP_SETFL(node->so_vnode, node->so_flag,
2930 2935 (node->so_state & (~FNONBLOCK)), CRED(), NULL);
2931 2936 }
2932 2937
2933 2938
2934 2939 /*
2935 2940 * Called by kernel sockets when the connection has been accepted or
2936 2941 * rejected. In early volo, a "disconnect" callback was sent instead of
2937 2942 * "connectfailed", so we check for both.
2938 2943 */
2939 2944 /* ARGSUSED */
2940 2945 void
2941 2946 idm_so_timed_socket_connect_cb(ksocket_t ks,
2942 2947 ksocket_callback_event_t ev, void *arg, uintptr_t info)
2943 2948 {
2944 2949 idm_so_timed_socket_t *itp = arg;
2945 2950 ASSERT(itp != NULL);
2946 2951 ASSERT(ev == KSOCKET_EV_CONNECTED ||
2947 2952 ev == KSOCKET_EV_CONNECTFAILED ||
2948 2953 ev == KSOCKET_EV_DISCONNECTED);
2949 2954
2950 2955 mutex_enter(&idm_so_timed_socket_mutex);
2951 2956 itp->it_callback_called = B_TRUE;
2952 2957 if (ev == KSOCKET_EV_CONNECTED) {
2953 2958 itp->it_socket_error_code = 0;
2954 2959 } else {
2955 2960 /* Make sure the error code is non-zero on error */
2956 2961 if (info == 0)
2957 2962 info = ECONNRESET;
2958 2963 itp->it_socket_error_code = (int)info;
2959 2964 }
2960 2965 cv_signal(&itp->it_cv);
2961 2966 mutex_exit(&idm_so_timed_socket_mutex);
2962 2967 }
2963 2968
2964 2969 int
2965 2970 idm_so_timed_socket_connect(ksocket_t ks,
2966 2971 struct sockaddr_storage *sa, int sa_sz, int login_max_usec)
2967 2972 {
2968 2973 clock_t conn_login_max;
2969 2974 int rc, nonblocking, rval;
2970 2975 idm_so_timed_socket_t it;
2971 2976 ksocket_callbacks_t ks_cb;
2972 2977
2973 2978 conn_login_max = ddi_get_lbolt() + drv_usectohz(login_max_usec);
2974 2979
2975 2980 /*
2976 2981 * Set to non-block socket mode, with callback on connect
2977 2982 * Early volo used "disconnected" instead of "connectfailed",
2978 2983 * so set callback to look for both.
2979 2984 */
2980 2985 bzero(&it, sizeof (it));
2981 2986 ks_cb.ksock_cb_flags = KSOCKET_CB_CONNECTED |
2982 2987 KSOCKET_CB_CONNECTFAILED | KSOCKET_CB_DISCONNECTED;
2983 2988 ks_cb.ksock_cb_connected = idm_so_timed_socket_connect_cb;
2984 2989 ks_cb.ksock_cb_connectfailed = idm_so_timed_socket_connect_cb;
2985 2990 ks_cb.ksock_cb_disconnected = idm_so_timed_socket_connect_cb;
2986 2991 cv_init(&it.it_cv, NULL, CV_DEFAULT, NULL);
2987 2992 rc = ksocket_setcallbacks(ks, &ks_cb, &it, CRED());
2988 2993 if (rc != 0)
2989 2994 return (rc);
2990 2995
2991 2996 /* Set to non-blocking mode */
2992 2997 nonblocking = 1;
2993 2998 rc = ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval,
2994 2999 CRED());
2995 3000 if (rc != 0)
2996 3001 goto cleanup;
2997 3002
2998 3003 bzero(&it, sizeof (it));
2999 3004 for (;;) {
3000 3005 /*
3001 3006 * Warning -- in a loopback scenario, the call to
3002 3007 * the connect_cb can occur inside the call to
3003 3008 * ksocket_connect. Do not hold the mutex around the
3004 3009 * call to ksocket_connect.
3005 3010 */
3006 3011 rc = ksocket_connect(ks, (struct sockaddr *)sa, sa_sz, CRED());
3007 3012 if (rc == 0 || rc == EISCONN) {
3008 3013 /* socket success or already success */
3009 3014 rc = 0;
3010 3015 break;
3011 3016 }
3012 3017 if ((rc != EINPROGRESS) && (rc != EALREADY)) {
3013 3018 break;
3014 3019 }
3015 3020
3016 3021 /* TCP connect still in progress. See if out of time. */
3017 3022 if (ddi_get_lbolt() > conn_login_max) {
3018 3023 /*
3019 3024 * Connection retry timeout,
3020 3025 * failed connect to target.
3021 3026 */
3022 3027 rc = ETIMEDOUT;
3023 3028 break;
3024 3029 }
3025 3030
3026 3031 /*
3027 3032 * TCP connect still in progress. Sleep until callback.
3028 3033 * Do NOT go to sleep if the callback already occurred!
3029 3034 */
3030 3035 mutex_enter(&idm_so_timed_socket_mutex);
3031 3036 if (!it.it_callback_called) {
3032 3037 (void) cv_timedwait(&it.it_cv,
3033 3038 &idm_so_timed_socket_mutex, conn_login_max);
3034 3039 }
3035 3040 if (it.it_callback_called) {
3036 3041 rc = it.it_socket_error_code;
3037 3042 mutex_exit(&idm_so_timed_socket_mutex);
3038 3043 break;
3039 3044 }
3040 3045 /* If timer expires, go call ksocket_connect one last time. */
3041 3046 mutex_exit(&idm_so_timed_socket_mutex);
3042 3047 }
3043 3048
3044 3049 /* resume blocking mode */
3045 3050 nonblocking = 0;
3046 3051 (void) ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval,
3047 3052 CRED());
3048 3053 cleanup:
3049 3054 (void) ksocket_setcallbacks(ks, NULL, NULL, CRED());
3050 3055 cv_destroy(&it.it_cv);
3051 3056 if (rc != 0) {
3052 3057 idm_soshutdown(ks);
3053 3058 }
3054 3059 return (rc);
3055 3060 }
3056 3061
3057 3062
3058 3063 void
3059 3064 idm_addr_to_sa(idm_addr_t *dportal, struct sockaddr_storage *sa)
3060 3065 {
3061 3066 int dp_addr_size;
3062 3067 struct sockaddr_in *sin;
3063 3068 struct sockaddr_in6 *sin6;
3064 3069
3065 3070 /* Build sockaddr_storage for this portal (idm_addr_t) */
3066 3071 bzero(sa, sizeof (*sa));
3067 3072 dp_addr_size = dportal->a_addr.i_insize;
3068 3073 if (dp_addr_size == sizeof (struct in_addr)) {
3069 3074 /* IPv4 */
3070 3075 sa->ss_family = AF_INET;
3071 3076 sin = (struct sockaddr_in *)sa;
3072 3077 sin->sin_port = htons(dportal->a_port);
3073 3078 bcopy(&dportal->a_addr.i_addr.in4,
3074 3079 &sin->sin_addr, sizeof (struct in_addr));
3075 3080 } else if (dp_addr_size == sizeof (struct in6_addr)) {
3076 3081 /* IPv6 */
3077 3082 sa->ss_family = AF_INET6;
3078 3083 sin6 = (struct sockaddr_in6 *)sa;
3079 3084 sin6->sin6_port = htons(dportal->a_port);
3080 3085 bcopy(&dportal->a_addr.i_addr.in6,
3081 3086 &sin6->sin6_addr, sizeof (struct in6_addr));
3082 3087 } else {
3083 3088 ASSERT(0);
3084 3089 }
3085 3090 }
3086 3091
3087 3092
3088 3093 /*
3089 3094 * return a human-readable form of a sockaddr_storage, in the form
3090 3095 * [ip-address]:port. This is used in calls to logging functions.
3091 3096 * If several calls to idm_sa_ntop are made within the same invocation
3092 3097 * of a logging function, then each one needs its own buf.
3093 3098 */
3094 3099 const char *
3095 3100 idm_sa_ntop(const struct sockaddr_storage *sa,
3096 3101 char *buf, size_t size)
3097 3102 {
3098 3103 static const char bogus_ip[] = "[0].-1";
3099 3104 char tmp[INET6_ADDRSTRLEN];
3100 3105
3101 3106 switch (sa->ss_family) {
3102 3107 case AF_INET6:
3103 3108 {
3104 3109 const struct sockaddr_in6 *in6 =
3105 3110 (const struct sockaddr_in6 *) sa;
3106 3111
3107 3112 if (inet_ntop(in6->sin6_family,
3108 3113 &in6->sin6_addr, tmp, sizeof (tmp)) == NULL) {
3109 3114 goto err;
3110 3115 }
3111 3116 if (strlen(tmp) + sizeof ("[].65535") > size) {
3112 3117 goto err;
3113 3118 }
3114 3119 /* struct sockaddr_storage gets port info from v4 loc */
3115 3120 (void) snprintf(buf, size, "[%s].%u", tmp,
3116 3121 ntohs(in6->sin6_port));
3117 3122 return (buf);
3118 3123 }
3119 3124 case AF_INET:
3120 3125 {
3121 3126 const struct sockaddr_in *in =
3122 3127 (const struct sockaddr_in *) sa;
3123 3128
3124 3129 if (inet_ntop(in->sin_family, &in->sin_addr,
3125 3130 tmp, sizeof (tmp)) == NULL) {
3126 3131 goto err;
3127 3132 }
3128 3133 if (strlen(tmp) + sizeof ("[].65535") > size) {
3129 3134 goto err;
3130 3135 }
3131 3136 (void) snprintf(buf, size, "[%s].%u", tmp,
3132 3137 ntohs(in->sin_port));
3133 3138 return (buf);
3134 3139 }
3135 3140 default:
3136 3141 break;
3137 3142 }
3138 3143 err:
3139 3144 (void) snprintf(buf, size, "%s", bogus_ip);
3140 3145 return (buf);
3141 3146 }
|
↓ open down ↓ |
1865 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX