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