1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2015 Alexander Motin <mav@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * without modification, immediately at the beginning of the file. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/param.h> 31 #include <sys/condvar.h> 32 #include <sys/conf.h> 33 #include <sys/eventhandler.h> 34 #include <sys/kernel.h> 35 #include <sys/kthread.h> 36 #include <sys/limits.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/module.h> 41 #include <sys/mutex.h> 42 #include <sys/proc.h> 43 #include <sys/queue.h> 44 #include <sys/socket.h> 45 #include <sys/socketvar.h> 46 #include <sys/sysctl.h> 47 #include <sys/systm.h> 48 #include <sys/uio.h> 49 #include <netinet/in.h> 50 #include <netinet/tcp.h> 51 #include <vm/uma.h> 52 53 #include <cam/cam.h> 54 #include <cam/scsi/scsi_all.h> 55 #include <cam/scsi/scsi_da.h> 56 #include <cam/ctl/ctl_io.h> 57 #include <cam/ctl/ctl.h> 58 #include <cam/ctl/ctl_frontend.h> 59 #include <cam/ctl/ctl_util.h> 60 #include <cam/ctl/ctl_backend.h> 61 #include <cam/ctl/ctl_ioctl.h> 62 #include <cam/ctl/ctl_ha.h> 63 #include <cam/ctl/ctl_private.h> 64 #include <cam/ctl/ctl_debug.h> 65 #include <cam/ctl/ctl_error.h> 66 67 struct ha_msg_wire { 68 uint32_t channel; 69 uint32_t length; 70 }; 71 72 struct ha_dt_msg_wire { 73 ctl_ha_dt_cmd command; 74 uint32_t size; 75 uint8_t *local; 76 uint8_t *remote; 77 }; 78 79 struct ha_softc { 80 struct ctl_softc *ha_ctl_softc; 81 ctl_evt_handler ha_handler[CTL_HA_CHAN_MAX]; 82 char ha_peer[128]; 83 struct sockaddr_in ha_peer_in; 84 struct socket *ha_lso; 85 struct socket *ha_so; 86 struct mbufq ha_sendq; 87 struct mbuf *ha_sending; 88 struct mtx ha_lock; 89 int ha_connect; 90 int ha_listen; 91 int ha_connected; 92 int ha_receiving; 93 int ha_wakeup; 94 int ha_disconnect; 95 int ha_shutdown; 96 eventhandler_tag ha_shutdown_eh; 97 TAILQ_HEAD(, ctl_ha_dt_req) ha_dts; 98 } ha_softc; 99 100 static void 101 ctl_ha_conn_wake(struct ha_softc *softc) 102 { 103 104 mtx_lock(&softc->ha_lock); 105 softc->ha_wakeup = 1; 106 mtx_unlock(&softc->ha_lock); 107 wakeup(&softc->ha_wakeup); 108 } 109 110 static int 111 ctl_ha_lupcall(struct socket *so, void *arg, int waitflag) 112 { 113 struct ha_softc *softc = arg; 114 115 ctl_ha_conn_wake(softc); 116 return (SU_OK); 117 } 118 119 static int 120 ctl_ha_rupcall(struct socket *so, void *arg, int waitflag) 121 { 122 struct ha_softc *softc = arg; 123 124 wakeup(&softc->ha_receiving); 125 return (SU_OK); 126 } 127 128 static int 129 ctl_ha_supcall(struct socket *so, void *arg, int waitflag) 130 { 131 struct ha_softc *softc = arg; 132 133 ctl_ha_conn_wake(softc); 134 return (SU_OK); 135 } 136 137 static void 138 ctl_ha_evt(struct ha_softc *softc, ctl_ha_channel ch, ctl_ha_event evt, 139 int param) 140 { 141 int i; 142 143 if (ch < CTL_HA_CHAN_MAX) { 144 if (softc->ha_handler[ch]) 145 softc->ha_handler[ch](ch, evt, param); 146 return; 147 } 148 for (i = 0; i < CTL_HA_CHAN_MAX; i++) { 149 if (softc->ha_handler[i]) 150 softc->ha_handler[i](i, evt, param); 151 } 152 } 153 154 static void 155 ctl_ha_close(struct ha_softc *softc) 156 { 157 struct socket *so = softc->ha_so; 158 int report = 0; 159 160 if (softc->ha_connected || softc->ha_disconnect) { 161 softc->ha_connected = 0; 162 mbufq_drain(&softc->ha_sendq); 163 m_freem(softc->ha_sending); 164 softc->ha_sending = NULL; 165 report = 1; 166 } 167 if (so) { 168 SOCKBUF_LOCK(&so->so_rcv); 169 soupcall_clear(so, SO_RCV); 170 while (softc->ha_receiving) { 171 wakeup(&softc->ha_receiving); 172 msleep(&softc->ha_receiving, SOCKBUF_MTX(&so->so_rcv), 173 0, "ha_rx exit", 0); 174 } 175 SOCKBUF_UNLOCK(&so->so_rcv); 176 SOCKBUF_LOCK(&so->so_snd); 177 soupcall_clear(so, SO_SND); 178 SOCKBUF_UNLOCK(&so->so_snd); 179 softc->ha_so = NULL; 180 if (softc->ha_connect) 181 pause("reconnect", hz / 2); 182 soclose(so); 183 } 184 if (report) { 185 ctl_ha_evt(softc, CTL_HA_CHAN_MAX, CTL_HA_EVT_LINK_CHANGE, 186 (softc->ha_connect || softc->ha_listen) ? 187 CTL_HA_LINK_UNKNOWN : CTL_HA_LINK_OFFLINE); 188 } 189 } 190 191 static void 192 ctl_ha_lclose(struct ha_softc *softc) 193 { 194 195 if (softc->ha_lso) { 196 if (SOLISTENING(softc->ha_lso)) { 197 SOLISTEN_LOCK(softc->ha_lso); 198 solisten_upcall_set(softc->ha_lso, NULL, NULL); 199 SOLISTEN_UNLOCK(softc->ha_lso); 200 } 201 soclose(softc->ha_lso); 202 softc->ha_lso = NULL; 203 } 204 } 205 206 static void 207 ctl_ha_rx_thread(void *arg) 208 { 209 struct ha_softc *softc = arg; 210 struct socket *so = softc->ha_so; 211 struct ha_msg_wire wire_hdr; 212 struct uio uio; 213 struct iovec iov; 214 int error, flags, next; 215 216 bzero(&wire_hdr, sizeof(wire_hdr)); 217 while (1) { 218 if (wire_hdr.length > 0) 219 next = wire_hdr.length; 220 else 221 next = sizeof(wire_hdr); 222 SOCKBUF_LOCK(&so->so_rcv); 223 while (sbavail(&so->so_rcv) < next || softc->ha_disconnect) { 224 if (softc->ha_connected == 0 || softc->ha_disconnect || 225 so->so_error || 226 (so->so_rcv.sb_state & SBS_CANTRCVMORE)) { 227 goto errout; 228 } 229 so->so_rcv.sb_lowat = next; 230 msleep(&softc->ha_receiving, SOCKBUF_MTX(&so->so_rcv), 231 0, "-", 0); 232 } 233 SOCKBUF_UNLOCK(&so->so_rcv); 234 235 if (wire_hdr.length == 0) { 236 iov.iov_base = &wire_hdr; 237 iov.iov_len = sizeof(wire_hdr); 238 uio.uio_iov = &iov; 239 uio.uio_iovcnt = 1; 240 uio.uio_rw = UIO_READ; 241 uio.uio_segflg = UIO_SYSSPACE; 242 uio.uio_td = curthread; 243 uio.uio_resid = sizeof(wire_hdr); 244 flags = MSG_DONTWAIT; 245 error = soreceive(softc->ha_so, NULL, &uio, NULL, 246 NULL, &flags); 247 if (error != 0) { 248 printf("%s: header receive error %d\n", 249 __func__, error); 250 SOCKBUF_LOCK(&so->so_rcv); 251 goto errout; 252 } 253 } else { 254 ctl_ha_evt(softc, wire_hdr.channel, 255 CTL_HA_EVT_MSG_RECV, wire_hdr.length); 256 wire_hdr.length = 0; 257 } 258 } 259 260 errout: 261 softc->ha_receiving = 0; 262 wakeup(&softc->ha_receiving); 263 SOCKBUF_UNLOCK(&so->so_rcv); 264 ctl_ha_conn_wake(softc); 265 kthread_exit(); 266 } 267 268 static void 269 ctl_ha_send(struct ha_softc *softc) 270 { 271 struct socket *so = softc->ha_so; 272 int error; 273 274 while (1) { 275 if (softc->ha_sending == NULL) { 276 mtx_lock(&softc->ha_lock); 277 softc->ha_sending = mbufq_dequeue(&softc->ha_sendq); 278 mtx_unlock(&softc->ha_lock); 279 if (softc->ha_sending == NULL) { 280 so->so_snd.sb_lowat = so->so_snd.sb_hiwat + 1; 281 break; 282 } 283 } 284 SOCKBUF_LOCK(&so->so_snd); 285 if (sbspace(&so->so_snd) < softc->ha_sending->m_pkthdr.len) { 286 so->so_snd.sb_lowat = softc->ha_sending->m_pkthdr.len; 287 SOCKBUF_UNLOCK(&so->so_snd); 288 break; 289 } 290 SOCKBUF_UNLOCK(&so->so_snd); 291 error = sosend(softc->ha_so, NULL, NULL, softc->ha_sending, 292 NULL, MSG_DONTWAIT, curthread); 293 softc->ha_sending = NULL; 294 if (error != 0) { 295 printf("%s: sosend() error %d\n", __func__, error); 296 return; 297 } 298 } 299 } 300 301 static void 302 ctl_ha_sock_setup(struct ha_softc *softc) 303 { 304 struct sockopt opt; 305 struct socket *so = softc->ha_so; 306 int error, val; 307 308 val = 1024 * 1024; 309 error = soreserve(so, val, val); 310 if (error) 311 printf("%s: soreserve failed %d\n", __func__, error); 312 313 SOCKBUF_LOCK(&so->so_rcv); 314 so->so_rcv.sb_lowat = sizeof(struct ha_msg_wire); 315 soupcall_set(so, SO_RCV, ctl_ha_rupcall, softc); 316 SOCKBUF_UNLOCK(&so->so_rcv); 317 SOCKBUF_LOCK(&so->so_snd); 318 so->so_snd.sb_lowat = sizeof(struct ha_msg_wire); 319 soupcall_set(so, SO_SND, ctl_ha_supcall, softc); 320 SOCKBUF_UNLOCK(&so->so_snd); 321 322 bzero(&opt, sizeof(struct sockopt)); 323 opt.sopt_dir = SOPT_SET; 324 opt.sopt_level = SOL_SOCKET; 325 opt.sopt_name = SO_KEEPALIVE; 326 opt.sopt_val = &val; 327 opt.sopt_valsize = sizeof(val); 328 val = 1; 329 error = sosetopt(so, &opt); 330 if (error) 331 printf("%s: KEEPALIVE setting failed %d\n", __func__, error); 332 333 opt.sopt_level = IPPROTO_TCP; 334 opt.sopt_name = TCP_NODELAY; 335 val = 1; 336 error = sosetopt(so, &opt); 337 if (error) 338 printf("%s: NODELAY setting failed %d\n", __func__, error); 339 340 opt.sopt_name = TCP_KEEPINIT; 341 val = 3; 342 error = sosetopt(so, &opt); 343 if (error) 344 printf("%s: KEEPINIT setting failed %d\n", __func__, error); 345 346 opt.sopt_name = TCP_KEEPIDLE; 347 val = 1; 348 error = sosetopt(so, &opt); 349 if (error) 350 printf("%s: KEEPIDLE setting failed %d\n", __func__, error); 351 352 opt.sopt_name = TCP_KEEPINTVL; 353 val = 1; 354 error = sosetopt(so, &opt); 355 if (error) 356 printf("%s: KEEPINTVL setting failed %d\n", __func__, error); 357 358 opt.sopt_name = TCP_KEEPCNT; 359 val = 5; 360 error = sosetopt(so, &opt); 361 if (error) 362 printf("%s: KEEPCNT setting failed %d\n", __func__, error); 363 } 364 365 static int 366 ctl_ha_connect(struct ha_softc *softc) 367 { 368 struct thread *td = curthread; 369 struct sockaddr_in sa; 370 struct socket *so; 371 int error; 372 373 /* Create the socket */ 374 error = socreate(PF_INET, &so, SOCK_STREAM, 375 IPPROTO_TCP, td->td_ucred, td); 376 if (error != 0) { 377 printf("%s: socreate() error %d\n", __func__, error); 378 return (error); 379 } 380 softc->ha_so = so; 381 ctl_ha_sock_setup(softc); 382 383 memcpy(&sa, &softc->ha_peer_in, sizeof(sa)); 384 error = soconnect(so, (struct sockaddr *)&sa, td); 385 if (error != 0) { 386 if (bootverbose) 387 printf("%s: soconnect() error %d\n", __func__, error); 388 goto out; 389 } 390 return (0); 391 392 out: 393 ctl_ha_close(softc); 394 return (error); 395 } 396 397 static int 398 ctl_ha_accept(struct ha_softc *softc) 399 { 400 struct socket *lso, *so; 401 struct sockaddr *sap; 402 int error; 403 404 lso = softc->ha_lso; 405 SOLISTEN_LOCK(lso); 406 error = solisten_dequeue(lso, &so, 0); 407 if (error == EWOULDBLOCK) 408 return (error); 409 if (error) { 410 printf("%s: socket error %d\n", __func__, error); 411 goto out; 412 } 413 414 sap = NULL; 415 error = soaccept(so, &sap); 416 if (error != 0) { 417 printf("%s: soaccept() error %d\n", __func__, error); 418 if (sap != NULL) 419 free(sap, M_SONAME); 420 goto out; 421 } 422 if (sap != NULL) 423 free(sap, M_SONAME); 424 softc->ha_so = so; 425 ctl_ha_sock_setup(softc); 426 return (0); 427 428 out: 429 ctl_ha_lclose(softc); 430 return (error); 431 } 432 433 static int 434 ctl_ha_listen(struct ha_softc *softc) 435 { 436 struct thread *td = curthread; 437 struct sockaddr_in sa; 438 struct sockopt opt; 439 int error, val; 440 441 /* Create the socket */ 442 if (softc->ha_lso == NULL) { 443 error = socreate(PF_INET, &softc->ha_lso, SOCK_STREAM, 444 IPPROTO_TCP, td->td_ucred, td); 445 if (error != 0) { 446 printf("%s: socreate() error %d\n", __func__, error); 447 return (error); 448 } 449 bzero(&opt, sizeof(struct sockopt)); 450 opt.sopt_dir = SOPT_SET; 451 opt.sopt_level = SOL_SOCKET; 452 opt.sopt_name = SO_REUSEADDR; 453 opt.sopt_val = &val; 454 opt.sopt_valsize = sizeof(val); 455 val = 1; 456 error = sosetopt(softc->ha_lso, &opt); 457 if (error) { 458 printf("%s: REUSEADDR setting failed %d\n", 459 __func__, error); 460 } 461 bzero(&opt, sizeof(struct sockopt)); 462 opt.sopt_dir = SOPT_SET; 463 opt.sopt_level = SOL_SOCKET; 464 opt.sopt_name = SO_REUSEPORT; 465 opt.sopt_val = &val; 466 opt.sopt_valsize = sizeof(val); 467 val = 1; 468 error = sosetopt(softc->ha_lso, &opt); 469 if (error) { 470 printf("%s: REUSEPORT setting failed %d\n", 471 __func__, error); 472 } 473 } 474 475 memcpy(&sa, &softc->ha_peer_in, sizeof(sa)); 476 error = sobind(softc->ha_lso, (struct sockaddr *)&sa, td); 477 if (error != 0) { 478 printf("%s: sobind() error %d\n", __func__, error); 479 goto out; 480 } 481 error = solisten(softc->ha_lso, 1, td); 482 if (error != 0) { 483 printf("%s: solisten() error %d\n", __func__, error); 484 goto out; 485 } 486 SOLISTEN_LOCK(softc->ha_lso); 487 softc->ha_lso->so_state |= SS_NBIO; 488 solisten_upcall_set(softc->ha_lso, ctl_ha_lupcall, softc); 489 SOLISTEN_UNLOCK(softc->ha_lso); 490 return (0); 491 492 out: 493 ctl_ha_lclose(softc); 494 return (error); 495 } 496 497 static void 498 ctl_ha_conn_thread(void *arg) 499 { 500 struct ha_softc *softc = arg; 501 int error; 502 503 while (1) { 504 if (softc->ha_disconnect || softc->ha_shutdown) { 505 ctl_ha_close(softc); 506 if (softc->ha_disconnect == 2 || softc->ha_shutdown) 507 ctl_ha_lclose(softc); 508 softc->ha_disconnect = 0; 509 if (softc->ha_shutdown) 510 break; 511 } else if (softc->ha_so != NULL && 512 (softc->ha_so->so_error || 513 softc->ha_so->so_rcv.sb_state & SBS_CANTRCVMORE)) 514 ctl_ha_close(softc); 515 if (softc->ha_so == NULL) { 516 if (softc->ha_lso != NULL) 517 ctl_ha_accept(softc); 518 else if (softc->ha_listen) 519 ctl_ha_listen(softc); 520 else if (softc->ha_connect) 521 ctl_ha_connect(softc); 522 } 523 if (softc->ha_so != NULL) { 524 if (softc->ha_connected == 0 && 525 softc->ha_so->so_error == 0 && 526 (softc->ha_so->so_state & SS_ISCONNECTING) == 0) { 527 softc->ha_connected = 1; 528 ctl_ha_evt(softc, CTL_HA_CHAN_MAX, 529 CTL_HA_EVT_LINK_CHANGE, 530 CTL_HA_LINK_ONLINE); 531 softc->ha_receiving = 1; 532 error = kproc_kthread_add(ctl_ha_rx_thread, 533 softc, &softc->ha_ctl_softc->ctl_proc, 534 NULL, 0, 0, "ctl", "ha_rx"); 535 if (error != 0) { 536 printf("Error creating CTL HA rx thread!\n"); 537 softc->ha_receiving = 0; 538 softc->ha_disconnect = 1; 539 } 540 } 541 ctl_ha_send(softc); 542 } 543 mtx_lock(&softc->ha_lock); 544 if (softc->ha_so != NULL && 545 (softc->ha_so->so_error || 546 softc->ha_so->so_rcv.sb_state & SBS_CANTRCVMORE)) 547 ; 548 else if (!softc->ha_wakeup) 549 msleep(&softc->ha_wakeup, &softc->ha_lock, 0, "-", hz); 550 softc->ha_wakeup = 0; 551 mtx_unlock(&softc->ha_lock); 552 } 553 mtx_lock(&softc->ha_lock); 554 softc->ha_shutdown = 2; 555 wakeup(&softc->ha_wakeup); 556 mtx_unlock(&softc->ha_lock); 557 kthread_exit(); 558 } 559 560 static int 561 ctl_ha_peer_sysctl(SYSCTL_HANDLER_ARGS) 562 { 563 struct ha_softc *softc = (struct ha_softc *)arg1; 564 struct sockaddr_in *sa; 565 int error, b1, b2, b3, b4, p, num; 566 char buf[128]; 567 568 strlcpy(buf, softc->ha_peer, sizeof(buf)); 569 error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 570 if ((error != 0) || (req->newptr == NULL) || 571 strncmp(buf, softc->ha_peer, sizeof(buf)) == 0) 572 return (error); 573 574 sa = &softc->ha_peer_in; 575 mtx_lock(&softc->ha_lock); 576 if ((num = sscanf(buf, "connect %d.%d.%d.%d:%d", 577 &b1, &b2, &b3, &b4, &p)) >= 4) { 578 softc->ha_connect = 1; 579 softc->ha_listen = 0; 580 } else if ((num = sscanf(buf, "listen %d.%d.%d.%d:%d", 581 &b1, &b2, &b3, &b4, &p)) >= 4) { 582 softc->ha_connect = 0; 583 softc->ha_listen = 1; 584 } else { 585 softc->ha_connect = 0; 586 softc->ha_listen = 0; 587 if (buf[0] != 0) { 588 buf[0] = 0; 589 error = EINVAL; 590 } 591 } 592 strlcpy(softc->ha_peer, buf, sizeof(softc->ha_peer)); 593 if (softc->ha_connect || softc->ha_listen) { 594 memset(sa, 0, sizeof(*sa)); 595 sa->sin_len = sizeof(struct sockaddr_in); 596 sa->sin_family = AF_INET; 597 sa->sin_port = htons((num >= 5) ? p : 999); 598 sa->sin_addr.s_addr = 599 htonl((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); 600 } 601 softc->ha_disconnect = 2; 602 softc->ha_wakeup = 1; 603 mtx_unlock(&softc->ha_lock); 604 wakeup(&softc->ha_wakeup); 605 return (error); 606 } 607 608 ctl_ha_status 609 ctl_ha_msg_register(ctl_ha_channel channel, ctl_evt_handler handler) 610 { 611 struct ha_softc *softc = &ha_softc; 612 613 KASSERT(channel < CTL_HA_CHAN_MAX, 614 ("Wrong CTL HA channel %d", channel)); 615 softc->ha_handler[channel] = handler; 616 return (CTL_HA_STATUS_SUCCESS); 617 } 618 619 ctl_ha_status 620 ctl_ha_msg_deregister(ctl_ha_channel channel) 621 { 622 struct ha_softc *softc = &ha_softc; 623 624 KASSERT(channel < CTL_HA_CHAN_MAX, 625 ("Wrong CTL HA channel %d", channel)); 626 softc->ha_handler[channel] = NULL; 627 return (CTL_HA_STATUS_SUCCESS); 628 } 629 630 /* 631 * Receive a message of the specified size. 632 */ 633 ctl_ha_status 634 ctl_ha_msg_recv(ctl_ha_channel channel, void *addr, size_t len, 635 int wait) 636 { 637 struct ha_softc *softc = &ha_softc; 638 struct uio uio; 639 struct iovec iov; 640 int error, flags; 641 642 if (!softc->ha_connected) 643 return (CTL_HA_STATUS_DISCONNECT); 644 645 iov.iov_base = addr; 646 iov.iov_len = len; 647 uio.uio_iov = &iov; 648 uio.uio_iovcnt = 1; 649 uio.uio_rw = UIO_READ; 650 uio.uio_segflg = UIO_SYSSPACE; 651 uio.uio_td = curthread; 652 uio.uio_resid = len; 653 flags = wait ? 0 : MSG_DONTWAIT; 654 error = soreceive(softc->ha_so, NULL, &uio, NULL, NULL, &flags); 655 if (error == 0) 656 return (CTL_HA_STATUS_SUCCESS); 657 658 /* Consider all errors fatal for HA sanity. */ 659 mtx_lock(&softc->ha_lock); 660 if (softc->ha_connected) { 661 softc->ha_disconnect = 1; 662 softc->ha_wakeup = 1; 663 wakeup(&softc->ha_wakeup); 664 } 665 mtx_unlock(&softc->ha_lock); 666 return (CTL_HA_STATUS_ERROR); 667 } 668 669 /* 670 * Send a message of the specified size. 671 */ 672 ctl_ha_status 673 ctl_ha_msg_send2(ctl_ha_channel channel, const void *addr, size_t len, 674 const void *addr2, size_t len2, int wait) 675 { 676 struct ha_softc *softc = &ha_softc; 677 struct mbuf *mb, *newmb; 678 struct ha_msg_wire hdr; 679 size_t copylen, off; 680 681 if (!softc->ha_connected) 682 return (CTL_HA_STATUS_DISCONNECT); 683 684 newmb = m_getm2(NULL, sizeof(hdr) + len + len2, wait, MT_DATA, 685 M_PKTHDR); 686 if (newmb == NULL) { 687 /* Consider all errors fatal for HA sanity. */ 688 mtx_lock(&softc->ha_lock); 689 if (softc->ha_connected) { 690 softc->ha_disconnect = 1; 691 softc->ha_wakeup = 1; 692 wakeup(&softc->ha_wakeup); 693 } 694 mtx_unlock(&softc->ha_lock); 695 printf("%s: Can't allocate mbuf chain\n", __func__); 696 return (CTL_HA_STATUS_ERROR); 697 } 698 hdr.channel = channel; 699 hdr.length = len + len2; 700 mb = newmb; 701 memcpy(mtodo(mb, 0), &hdr, sizeof(hdr)); 702 mb->m_len += sizeof(hdr); 703 off = 0; 704 for (; mb != NULL && off < len; mb = mb->m_next) { 705 copylen = min(M_TRAILINGSPACE(mb), len - off); 706 memcpy(mtodo(mb, mb->m_len), (const char *)addr + off, copylen); 707 mb->m_len += copylen; 708 off += copylen; 709 if (off == len) 710 break; 711 } 712 KASSERT(off == len, ("%s: off (%zu) != len (%zu)", __func__, 713 off, len)); 714 off = 0; 715 for (; mb != NULL && off < len2; mb = mb->m_next) { 716 copylen = min(M_TRAILINGSPACE(mb), len2 - off); 717 memcpy(mtodo(mb, mb->m_len), (const char *)addr2 + off, copylen); 718 mb->m_len += copylen; 719 off += copylen; 720 } 721 KASSERT(off == len2, ("%s: off (%zu) != len2 (%zu)", __func__, 722 off, len2)); 723 newmb->m_pkthdr.len = sizeof(hdr) + len + len2; 724 725 mtx_lock(&softc->ha_lock); 726 if (!softc->ha_connected) { 727 mtx_unlock(&softc->ha_lock); 728 m_freem(newmb); 729 return (CTL_HA_STATUS_DISCONNECT); 730 } 731 mbufq_enqueue(&softc->ha_sendq, newmb); 732 softc->ha_wakeup = 1; 733 mtx_unlock(&softc->ha_lock); 734 wakeup(&softc->ha_wakeup); 735 return (CTL_HA_STATUS_SUCCESS); 736 } 737 738 ctl_ha_status 739 ctl_ha_msg_send(ctl_ha_channel channel, const void *addr, size_t len, 740 int wait) 741 { 742 743 return (ctl_ha_msg_send2(channel, addr, len, NULL, 0, wait)); 744 } 745 746 ctl_ha_status 747 ctl_ha_msg_abort(ctl_ha_channel channel) 748 { 749 struct ha_softc *softc = &ha_softc; 750 751 mtx_lock(&softc->ha_lock); 752 softc->ha_disconnect = 1; 753 softc->ha_wakeup = 1; 754 mtx_unlock(&softc->ha_lock); 755 wakeup(&softc->ha_wakeup); 756 return (CTL_HA_STATUS_SUCCESS); 757 } 758 759 /* 760 * Allocate a data transfer request structure. 761 */ 762 struct ctl_ha_dt_req * 763 ctl_dt_req_alloc(void) 764 { 765 766 return (malloc(sizeof(struct ctl_ha_dt_req), M_CTL, M_WAITOK | M_ZERO)); 767 } 768 769 /* 770 * Free a data transfer request structure. 771 */ 772 void 773 ctl_dt_req_free(struct ctl_ha_dt_req *req) 774 { 775 776 free(req, M_CTL); 777 } 778 779 /* 780 * Issue a DMA request for a single buffer. 781 */ 782 ctl_ha_status 783 ctl_dt_single(struct ctl_ha_dt_req *req) 784 { 785 struct ha_softc *softc = &ha_softc; 786 struct ha_dt_msg_wire wire_dt; 787 ctl_ha_status status; 788 789 wire_dt.command = req->command; 790 wire_dt.size = req->size; 791 wire_dt.local = req->local; 792 wire_dt.remote = req->remote; 793 if (req->command == CTL_HA_DT_CMD_READ && req->callback != NULL) { 794 mtx_lock(&softc->ha_lock); 795 TAILQ_INSERT_TAIL(&softc->ha_dts, req, links); 796 mtx_unlock(&softc->ha_lock); 797 ctl_ha_msg_send(CTL_HA_CHAN_DATA, &wire_dt, sizeof(wire_dt), 798 M_WAITOK); 799 return (CTL_HA_STATUS_WAIT); 800 } 801 if (req->command == CTL_HA_DT_CMD_READ) { 802 status = ctl_ha_msg_send(CTL_HA_CHAN_DATA, &wire_dt, 803 sizeof(wire_dt), M_WAITOK); 804 } else { 805 status = ctl_ha_msg_send2(CTL_HA_CHAN_DATA, &wire_dt, 806 sizeof(wire_dt), req->local, req->size, M_WAITOK); 807 } 808 return (status); 809 } 810 811 static void 812 ctl_dt_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) 813 { 814 struct ha_softc *softc = &ha_softc; 815 struct ctl_ha_dt_req *req; 816 ctl_ha_status isc_status; 817 818 if (event == CTL_HA_EVT_MSG_RECV) { 819 struct ha_dt_msg_wire wire_dt; 820 uint8_t *tmp; 821 int size; 822 823 size = min(sizeof(wire_dt), param); 824 isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_DATA, &wire_dt, 825 size, M_WAITOK); 826 if (isc_status != CTL_HA_STATUS_SUCCESS) { 827 printf("%s: Error receiving message: %d\n", 828 __func__, isc_status); 829 return; 830 } 831 832 if (wire_dt.command == CTL_HA_DT_CMD_READ) { 833 wire_dt.command = CTL_HA_DT_CMD_WRITE; 834 tmp = wire_dt.local; 835 wire_dt.local = wire_dt.remote; 836 wire_dt.remote = tmp; 837 ctl_ha_msg_send2(CTL_HA_CHAN_DATA, &wire_dt, 838 sizeof(wire_dt), wire_dt.local, wire_dt.size, 839 M_WAITOK); 840 } else if (wire_dt.command == CTL_HA_DT_CMD_WRITE) { 841 isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_DATA, 842 wire_dt.remote, wire_dt.size, M_WAITOK); 843 mtx_lock(&softc->ha_lock); 844 TAILQ_FOREACH(req, &softc->ha_dts, links) { 845 if (req->local == wire_dt.remote) { 846 TAILQ_REMOVE(&softc->ha_dts, req, links); 847 break; 848 } 849 } 850 mtx_unlock(&softc->ha_lock); 851 if (req) { 852 req->ret = isc_status; 853 req->callback(req); 854 } 855 } 856 } else if (event == CTL_HA_EVT_LINK_CHANGE) { 857 CTL_DEBUG_PRINT(("%s: Link state change to %d\n", __func__, 858 param)); 859 if (param != CTL_HA_LINK_ONLINE) { 860 mtx_lock(&softc->ha_lock); 861 while ((req = TAILQ_FIRST(&softc->ha_dts)) != NULL) { 862 TAILQ_REMOVE(&softc->ha_dts, req, links); 863 mtx_unlock(&softc->ha_lock); 864 req->ret = CTL_HA_STATUS_DISCONNECT; 865 req->callback(req); 866 mtx_lock(&softc->ha_lock); 867 } 868 mtx_unlock(&softc->ha_lock); 869 } 870 } else { 871 printf("%s: Unknown event %d\n", __func__, event); 872 } 873 } 874 875 ctl_ha_status 876 ctl_ha_msg_init(struct ctl_softc *ctl_softc) 877 { 878 struct ha_softc *softc = &ha_softc; 879 int error; 880 881 softc->ha_ctl_softc = ctl_softc; 882 mtx_init(&softc->ha_lock, "CTL HA mutex", NULL, MTX_DEF); 883 mbufq_init(&softc->ha_sendq, INT_MAX); 884 TAILQ_INIT(&softc->ha_dts); 885 error = kproc_kthread_add(ctl_ha_conn_thread, softc, 886 &ctl_softc->ctl_proc, NULL, 0, 0, "ctl", "ha_tx"); 887 if (error != 0) { 888 printf("error creating CTL HA connection thread!\n"); 889 mtx_destroy(&softc->ha_lock); 890 return (CTL_HA_STATUS_ERROR); 891 } 892 softc->ha_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, 893 ctl_ha_msg_shutdown, ctl_softc, SHUTDOWN_PRI_FIRST); 894 SYSCTL_ADD_PROC(&ctl_softc->sysctl_ctx, 895 SYSCTL_CHILDREN(ctl_softc->sysctl_tree), 896 OID_AUTO, "ha_peer", 897 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 898 softc, 0, ctl_ha_peer_sysctl, "A", "HA peer connection method"); 899 900 if (ctl_ha_msg_register(CTL_HA_CHAN_DATA, ctl_dt_event_handler) 901 != CTL_HA_STATUS_SUCCESS) { 902 printf("%s: ctl_ha_msg_register failed.\n", __func__); 903 } 904 905 return (CTL_HA_STATUS_SUCCESS); 906 }; 907 908 void 909 ctl_ha_msg_shutdown(struct ctl_softc *ctl_softc) 910 { 911 struct ha_softc *softc = &ha_softc; 912 913 /* Disconnect and shutdown threads. */ 914 mtx_lock(&softc->ha_lock); 915 if (softc->ha_shutdown < 2) { 916 softc->ha_shutdown = 1; 917 softc->ha_wakeup = 1; 918 wakeup(&softc->ha_wakeup); 919 while (softc->ha_shutdown < 2 && !SCHEDULER_STOPPED()) { 920 msleep(&softc->ha_wakeup, &softc->ha_lock, 0, 921 "shutdown", hz); 922 } 923 } 924 mtx_unlock(&softc->ha_lock); 925 }; 926 927 ctl_ha_status 928 ctl_ha_msg_destroy(struct ctl_softc *ctl_softc) 929 { 930 struct ha_softc *softc = &ha_softc; 931 932 if (softc->ha_shutdown_eh != NULL) { 933 EVENTHANDLER_DEREGISTER(shutdown_pre_sync, 934 softc->ha_shutdown_eh); 935 softc->ha_shutdown_eh = NULL; 936 } 937 938 ctl_ha_msg_shutdown(ctl_softc); /* Just in case. */ 939 940 if (ctl_ha_msg_deregister(CTL_HA_CHAN_DATA) != CTL_HA_STATUS_SUCCESS) 941 printf("%s: ctl_ha_msg_deregister failed.\n", __func__); 942 943 mtx_destroy(&softc->ha_lock); 944 return (CTL_HA_STATUS_SUCCESS); 945 }; 946