1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2012 Milan Jurik. All rights reserved. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/socket.h> 30 #include <signal.h> 31 #include <locale.h> 32 #include <syslog.h> 33 #include <netdb.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <fcntl.h> 37 #include <unistd.h> 38 #include <stdio.h> 39 #include <errno.h> 40 #include <door.h> 41 #include <meta.h> 42 #include <libsysevent.h> 43 #include <wait.h> 44 #include <semaphore.h> 45 #include <libscf.h> 46 47 #include <sys/scsi/adapters/iscsi_door.h> 48 #include <sys/scsi/adapters/iscsi_if.h> 49 50 /* 51 * Local Defines 52 * ------------- 53 */ 54 #define ISCSI_DOOR_DAEMON_SYSLOG_PP "iscsid" 55 #define ISCSI_DISCOVERY_POLL_DELAY1 1 /* Seconds */ 56 #define ISCSI_DISCOVERY_POLL_DELAY2 60 /* Seconds */ 57 #define ISCSI_SMF_OFFLINE_DELAY 10 /* Seconds */ 58 #define ISCSI_SMF_OFFLINE_MAX_RETRY_TIMES 60 59 60 #if !defined(SMF_EXIT_ERR_OTHER) 61 #define SMF_EXIT_ERR_OTHER -1 62 #endif 63 64 /* 65 * Global Variables related to the synchronization of the child process 66 * -------------------------------------------------------------------- 67 */ 68 static pid_t iscsi_child_pid; 69 static sem_t iscsi_child_sem; 70 static int iscsi_child_door_handle; 71 static int iscsi_child_smf_exit_code; 72 73 /* 74 * Global Variables related to the door accessed by the kernel 75 * ----------------------------------------------------------- 76 */ 77 static int iscsi_dev_handle; 78 static int iscsi_kernel_door_handle; 79 80 /* 81 * Prototypes of Functions the body of which is defined farther down 82 * in this file. 83 * ----------------------------------------------------------------- 84 */ 85 static void call_child_door(int value); 86 static void sigchld_handler(int sig); 87 static boolean_t discovery_event_wait(int did); 88 static void signone(int, siginfo_t *, void *); 89 90 static 91 void 92 iscsi_child_door( 93 void *cookie, 94 char *args, 95 size_t alen, 96 door_desc_t *ddp, 97 uint_t ndid 98 ); 99 100 static 101 void 102 iscsi_kernel_door( 103 void *cookie, 104 char *args, 105 size_t alen, 106 door_desc_t *ddp, 107 uint_t ndid 108 ); 109 110 static 111 iscsi_door_cnf_t * 112 _getipnodebyname_req( 113 getipnodebyname_req_t *req, 114 int req_len, 115 size_t *pcnf_len 116 ); 117 118 /* 119 * main -- Entry point of the iSCSI door server daemon 120 * 121 * This function forks, waits for the child process feedback and exits. 122 */ 123 /* ARGSUSED */ 124 int 125 main( 126 int argc, 127 char *argv[] 128 ) 129 { 130 int i; 131 int sig; 132 int ret = -1; 133 int retry = 0; 134 sigset_t sigs, allsigs; 135 struct sigaction act; 136 uint32_t rval; 137 138 /* 139 * Get the locale set up before calling any other routines 140 * with messages to ouput. 141 */ 142 (void) setlocale(LC_ALL, ""); 143 openlog("ISCSI_DOOR_DAEMON_SYSLOG_PP", LOG_PID, LOG_DAEMON); 144 145 /* The child semaphore is created. */ 146 if (sem_init(&iscsi_child_sem, 0, 0) == -1) { 147 exit(SMF_EXIT_ERR_OTHER); 148 } 149 150 /* The door for the child is created. */ 151 iscsi_child_door_handle = door_create(iscsi_child_door, NULL, 0); 152 if (iscsi_child_door_handle == -1) { 153 (void) sem_destroy(&iscsi_child_sem); 154 exit(SMF_EXIT_ERR_OTHER); 155 } 156 157 /* A signal handler is set for SIGCHLD. */ 158 (void) signal(SIGCHLD, sigchld_handler); 159 160 /* 161 * Here begins the daemonizing code 162 * -------------------------------- 163 */ 164 iscsi_child_pid = fork(); 165 if (iscsi_child_pid < 0) { 166 /* The fork failed. */ 167 syslog(LOG_DAEMON | LOG_ERR, gettext("Cannot fork")); 168 (void) sem_destroy(&iscsi_child_sem); 169 exit(SMF_EXIT_ERR_OTHER); 170 } 171 172 if (iscsi_child_pid) { 173 /* 174 * The parent exits after the child has provided feedback. This 175 * waiting phase is to meet one of greenline's requirements. 176 * We shouldn't return till we are sure the service is ready to 177 * be provided. 178 */ 179 (void) sem_wait(&iscsi_child_sem); 180 (void) sem_destroy(&iscsi_child_sem); 181 exit(iscsi_child_smf_exit_code); 182 } 183 184 /* 185 * stdout and stderr are redirected to "/dev/null". 186 */ 187 i = open("/dev/null", O_RDWR); 188 (void) dup2(i, 1); 189 (void) dup2(i, 2); 190 191 /* 192 * Here ends the daemonizing code 193 * ------------------------------ 194 */ 195 196 /* 197 * Block out all signals 198 */ 199 (void) sigfillset(&allsigs); 200 (void) pthread_sigmask(SIG_BLOCK, &allsigs, NULL); 201 202 /* setup the door handle */ 203 iscsi_kernel_door_handle = door_create(iscsi_kernel_door, NULL, 0); 204 if (iscsi_kernel_door_handle == -1) { 205 perror(gettext("door_create failed")); 206 syslog(LOG_DAEMON | LOG_ERR, gettext("door_create failed")); 207 exit(SMF_EXIT_ERR_OTHER); 208 } 209 210 /* 211 * The iSCSI driver is opened. 212 */ 213 iscsi_dev_handle = open(ISCSI_DRIVER_DEVCTL, O_RDWR); 214 if (iscsi_dev_handle == -1) { 215 /* The driver couldn't be opened. */ 216 perror(gettext("iscsi device open failed")); 217 exit(SMF_EXIT_ERR_OTHER); 218 } 219 220 if (ioctl( 221 iscsi_dev_handle, 222 ISCSI_SMF_ONLINE, 223 &iscsi_kernel_door_handle) == -1) { 224 (void) close(iscsi_dev_handle); 225 perror(gettext("ioctl: enable iscsi initiator")); 226 exit(SMF_EXIT_ERR_OTHER); 227 } 228 229 /* 230 * Keep the dev open, so to keep iscsi module from unloaded. 231 * This is crutial to guarantee the consistency of the 232 * door_handle and service state in kernel. 233 */ 234 235 /* We have to wait for the discovery process to finish. */ 236 (void) discovery_event_wait(iscsi_dev_handle); 237 238 /* We let the parent know that everything is ok. */ 239 call_child_door(SMF_EXIT_OK); 240 241 /* now set up signals we care about */ 242 243 (void) sigemptyset(&sigs); 244 (void) sigaddset(&sigs, SIGTERM); 245 (void) sigaddset(&sigs, SIGINT); 246 (void) sigaddset(&sigs, SIGQUIT); 247 248 /* make sure signals to be enqueued */ 249 act.sa_flags = SA_SIGINFO; 250 act.sa_sigaction = signone; 251 252 (void) sigaction(SIGTERM, &act, NULL); 253 (void) sigaction(SIGINT, &act, NULL); 254 (void) sigaction(SIGQUIT, &act, NULL); 255 256 /* wait and process signals */ 257 for (;;) { 258 sig = sigwait(&sigs); 259 if (sig < 0) 260 continue; 261 switch (sig) { 262 case SIGQUIT: 263 case SIGINT: 264 case SIGTERM: 265 do { 266 ret = ioctl(iscsi_dev_handle, 267 ISCSI_SMF_OFFLINE, &rval); 268 if (ret == -1) { 269 /* 270 * Keep retrying if unable 271 * to stop 272 */ 273 (void) sleep(ISCSI_SMF_OFFLINE_DELAY); 274 retry++; 275 } 276 } while ((ret == -1) && 277 (retry < ISCSI_SMF_OFFLINE_MAX_RETRY_TIMES)); 278 (void) close(iscsi_dev_handle); 279 if (rval == B_FALSE) { 280 syslog(LOG_DAEMON, gettext("iSCSI initiator" 281 " service exited with sessions left.")); 282 } 283 return (0); 284 default: 285 break; 286 } 287 } 288 } 289 290 /* 291 * sigchld_handler -- SIGCHLD Handler 292 * 293 */ 294 /* ARGSUSED */ 295 static 296 void 297 sigchld_handler( 298 int sig 299 ) 300 { 301 int status; 302 pid_t ret_pid; 303 304 /* This is the default code. */ 305 iscsi_child_smf_exit_code = SMF_EXIT_ERR_OTHER; 306 307 ret_pid = waitpid(iscsi_child_pid, &status, WNOHANG); 308 309 if (ret_pid == iscsi_child_pid) { 310 if (WIFEXITED(status)) { 311 iscsi_child_smf_exit_code = WEXITSTATUS(status); 312 } 313 } 314 (void) sem_post(&iscsi_child_sem); 315 } 316 317 /* 318 * iscsi_child_door -- Child process door entry point 319 * 320 * This function is executed when a driver calls door_ki_upcall(). 321 */ 322 /* ARGSUSED */ 323 static 324 void 325 iscsi_child_door( 326 void *cookie, 327 char *args, 328 size_t alen, 329 door_desc_t *ddp, 330 uint_t ndid 331 ) 332 { 333 int *ptr = (int *)args; 334 335 iscsi_child_smf_exit_code = SMF_EXIT_ERR_OTHER; 336 337 if (alen >= sizeof (iscsi_child_smf_exit_code)) { 338 iscsi_child_smf_exit_code = *ptr; 339 } 340 (void) sem_post(&iscsi_child_sem); 341 (void) door_return(NULL, 0, NULL, 0); 342 } 343 344 /* 345 * iscsi_kernel_door -- Kernel door entry point 346 * 347 * This function is executed when a driver calls door_ki_upcall(). 348 */ 349 /* ARGSUSED */ 350 static 351 void 352 iscsi_kernel_door( 353 void *cookie, 354 char *args, 355 size_t alen, 356 door_desc_t *ddp, 357 uint_t ndid 358 ) 359 { 360 iscsi_door_msg_hdr_t err_ind; 361 iscsi_door_req_t *req; 362 iscsi_door_cnf_t *cnf; 363 size_t cnf_len; 364 char *err_txt; 365 int err_code; 366 367 /* Local variables pre-initialization */ 368 err_ind.signature = ISCSI_DOOR_REQ_SIGNATURE; 369 err_ind.version = ISCSI_DOOR_REQ_VERSION_1; 370 err_ind.opcode = ISCSI_DOOR_ERROR_IND; 371 372 req = (iscsi_door_req_t *)args; 373 cnf = (iscsi_door_cnf_t *)&err_ind; 374 cnf_len = sizeof (err_ind); 375 376 /* 377 * The validity of the request is checked before going any farther. 378 */ 379 if (req == NULL) { 380 /* 381 * A request has to be passed. 382 */ 383 err_ind.status = ISCSI_DOOR_STATUS_REQ_INVALID; 384 } else if (alen < sizeof (iscsi_door_msg_hdr_t)) { 385 /* 386 * The buffer containing the request must be at least as big 387 * as message header. 388 */ 389 err_ind.status = ISCSI_DOOR_STATUS_REQ_LENGTH; 390 } else if (req->hdr.signature != ISCSI_DOOR_REQ_SIGNATURE) { 391 /* 392 * The request must be correctly signed. 393 */ 394 err_ind.status = ISCSI_DOOR_STATUS_REQ_INVALID; 395 } else if (req->hdr.version != ISCSI_DOOR_REQ_VERSION_1) { 396 /* 397 * The version of the request must be supported by the server. 398 */ 399 err_ind.status = ISCSI_DOOR_STATUS_REQ_VERSION; 400 } else { 401 /* 402 * The request is treated according to the opcode. 403 */ 404 switch (req->hdr.opcode) { 405 406 case ISCSI_DOOR_GETIPNODEBYNAME_REQ: 407 cnf = _getipnodebyname_req( 408 &req->ginbn_req, 409 alen, 410 &cnf_len); 411 break; 412 default: 413 err_ind.status = ISCSI_DOOR_STATUS_REQ_INVALID; 414 break; 415 } 416 } 417 err_code = door_return((char *)cnf, cnf_len, NULL, 0); 418 419 switch (err_code) { 420 case E2BIG: 421 err_txt = "E2BIG"; 422 break; 423 case EFAULT: 424 err_txt = "EFAULT"; 425 break; 426 case EINVAL: 427 err_txt = "EINVAL"; 428 break; 429 case EMFILE: 430 err_txt = "EMFILE"; 431 break; 432 default: 433 err_txt = "?"; 434 break; 435 } 436 (void) fprintf(stderr, "door_return error(%s,%d)", err_txt, err_code); 437 syslog( 438 LOG_DAEMON | LOG_ERR, 439 gettext("!door_return error(%s,%d)"), 440 err_txt, 441 err_code); 442 } 443 444 /* 445 * _getipnodebyname_req 446 * 447 * This function executes the request ISCSI_DOOR_GETIPNODEBYNAME_REQ. It 448 * calls getipnodebyname() but doesn't return all the information. The 449 * confirmation structure only contains one IP address of the list returned 450 * by getipnodebyname(). 451 */ 452 static 453 iscsi_door_cnf_t * 454 _getipnodebyname_req( 455 getipnodebyname_req_t *req, 456 int req_len, 457 size_t *pcnf_len 458 ) { 459 getipnodebyname_cnf_t *cnf = (getipnodebyname_cnf_t *)req; 460 size_t cnf_len; 461 struct hostent *hptr; 462 char *name; 463 464 /* The opcode is changed immediately. */ 465 cnf->hdr.opcode = ISCSI_DOOR_GETIPNODEBYNAME_CNF; 466 467 /* The size of the request is checked against the minimum required. */ 468 if (req_len < sizeof (getipnodebyname_cnf_t)) { 469 cnf->hdr.status = ISCSI_DOOR_STATUS_REQ_FORMAT; 470 *pcnf_len = req_len; 471 return ((iscsi_door_cnf_t *)cnf); 472 } 473 474 name = (char *)req + req->name_offset; 475 476 /* 477 * The pointer to the name has to stay inside the request but 478 * after the header. 479 */ 480 if ((name < ((char *)req + sizeof (getipnodebyname_req_t))) || 481 ((name + req->name_length) > ((char *)req + req_len))) { 482 cnf->hdr.status = ISCSI_DOOR_STATUS_REQ_FORMAT; 483 *pcnf_len = req_len; 484 return ((iscsi_door_cnf_t *)cnf); 485 } 486 487 /* The library function is called. */ 488 hptr = getipnodebyname( 489 name, 490 (int)req->af, 491 (int)req->flags, 492 (int *)&cnf->error_num); 493 494 if (hptr) { 495 /* 496 * The call was successful. Now starts the painful work of 497 * parsing the data. However, for version 1 we will only 498 * return the first address. 499 */ 500 cnf_len = sizeof (getipnodebyname_cnf_t); 501 cnf->h_size_needed = sizeof (getipnodebyname_cnf_t); 502 cnf->h_alias_list_length = 0; 503 cnf->h_alias_list_offset = 0; 504 cnf->h_name_len = 0; 505 cnf->h_name_offset = 0; 506 507 cnf->h_addrlen = (uint32_t)hptr->h_length; 508 cnf->h_addrtype = (uint32_t)hptr->h_addrtype; 509 cnf->h_addr_list_offset = sizeof (getipnodebyname_cnf_t); 510 511 if (*hptr->h_addr_list != NULL) { 512 (void) memcpy( 513 ((char *)cnf + sizeof (getipnodebyname_cnf_t)), 514 *hptr->h_addr_list, 515 hptr->h_length); 516 cnf->h_addr_list_length = 1; 517 cnf->h_size_needed += cnf->h_addrlen; 518 cnf_len += hptr->h_length; 519 } else { 520 cnf->h_addr_list_length = 0; 521 cnf->h_size_needed += hptr->h_length; 522 } 523 *pcnf_len = cnf_len; 524 cnf->hdr.status = ISCSI_DOOR_STATUS_SUCCESS; 525 freehostent(hptr); 526 } else { 527 cnf->hdr.status = ISCSI_DOOR_STATUS_SUCCESS; 528 cnf->h_addrlen = 0; 529 cnf->h_addrtype = 0; 530 cnf->h_addr_list_offset = sizeof (getipnodebyname_cnf_t); 531 cnf->h_addr_list_length = 0; 532 cnf->h_name_offset = sizeof (getipnodebyname_cnf_t); 533 cnf->h_name_len = 0; 534 cnf->h_alias_list_offset = sizeof (getipnodebyname_cnf_t); 535 cnf->h_alias_list_length = 0; 536 cnf->h_size_needed = sizeof (getipnodebyname_cnf_t); 537 *pcnf_len = sizeof (getipnodebyname_cnf_t); 538 } 539 return ((iscsi_door_cnf_t *)cnf); 540 } 541 542 /* 543 * call_child_door -- This function calls the child door with the value 544 * provided by the caller. 545 * 546 */ 547 static 548 void 549 call_child_door( 550 int value 551 ) 552 { 553 door_arg_t door_arg; 554 555 (void) memset(&door_arg, 0, sizeof (door_arg)); 556 door_arg.data_ptr = (char *)&value; 557 door_arg.data_size = sizeof (value); 558 (void) door_call(iscsi_child_door_handle, &door_arg); 559 } 560 561 /* 562 * get_luns_count -- 563 */ 564 static 565 uint32_t 566 get_luns_count( 567 int did 568 ) 569 { 570 iscsi_lun_list_t *lun_list; 571 iscsi_lun_list_t *tmp; 572 size_t len; 573 uint32_t lun_count; 574 575 lun_list = (iscsi_lun_list_t *)malloc(sizeof (*lun_list)); 576 577 (void) memset(lun_list, 0, sizeof (*lun_list)); 578 lun_list->ll_vers = ISCSI_INTERFACE_VERSION; 579 lun_list->ll_in_cnt = 1; 580 lun_list->ll_all_tgts = B_TRUE; 581 582 for (;;) { 583 584 if (ioctl( 585 did, 586 ISCSI_LUN_OID_LIST_GET, 587 lun_list) == -1) { 588 free(lun_list); 589 /* The Ioctl didn't go well. */ 590 return (0); 591 } 592 if (lun_list->ll_in_cnt >= lun_list->ll_out_cnt) { 593 /* We got it all. */ 594 break; 595 } 596 /* 597 * We didn't get all the targets. Let's build a new Ioctl with 598 * a new size. 599 */ 600 tmp = lun_list; 601 len = tmp->ll_out_cnt * sizeof (tmp->ll_luns); 602 len += sizeof (*tmp) - sizeof (tmp->ll_luns); 603 lun_list = (iscsi_lun_list_t *)malloc(len); 604 if (lun_list == NULL) { 605 /* No resources. */ 606 free(tmp); 607 return (0); 608 } 609 (void) memset(lun_list, 0, len); 610 lun_list->ll_vers = ISCSI_INTERFACE_VERSION; 611 lun_list->ll_in_cnt = tmp->ll_out_cnt; 612 lun_list->ll_all_tgts = B_TRUE; 613 free(tmp); 614 } 615 lun_count = lun_list->ll_out_cnt; 616 free(lun_list); 617 return (lun_count); 618 } 619 620 /* 621 * discovery_event_wait -- Waits for the discovery process to finish. 622 * 623 */ 624 static 625 boolean_t 626 discovery_event_wait( 627 int did 628 ) 629 { 630 boolean_t rc; 631 uint32_t lun_count; 632 uint32_t lun_timer; 633 uint32_t tmp; 634 iSCSIDiscoveryMethod_t discovery_flags; 635 iSCSIDiscoveryMethod_t discovery_all; 636 637 rc = B_FALSE; 638 lun_count = 0; 639 lun_timer = 0; 640 discovery_flags = 0; 641 discovery_all = iSCSIDiscoveryMethodStatic | 642 iSCSIDiscoveryMethodSLP | 643 iSCSIDiscoveryMethodISNS | 644 iSCSIDiscoveryMethodSendTargets; 645 646 for (;;) { 647 648 /* The status discovery flags are read. */ 649 if (ioctl( 650 did, 651 ISCSI_DISCOVERY_EVENTS, 652 &discovery_flags) == -1) { 653 /* IO problem */ 654 break; 655 } 656 657 if (discovery_flags == discovery_all) { 658 /* Discovery over */ 659 rc = B_TRUE; 660 break; 661 } 662 663 if (lun_timer >= ISCSI_DISCOVERY_POLL_DELAY2) { 664 /* Let's check if the driver is making progress. */ 665 tmp = get_luns_count(did); 666 if (tmp <= lun_count) { 667 /* No progress */ 668 break; 669 } 670 lun_count = tmp; 671 lun_timer = 0; 672 } 673 (void) sleep(ISCSI_DISCOVERY_POLL_DELAY1); 674 lun_timer += ISCSI_DISCOVERY_POLL_DELAY1; 675 } 676 return (rc); 677 } 678 679 /*ARGSUSED*/ 680 static void 681 signone(int sig, siginfo_t *sip, void *utp) 682 { 683 } 684