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