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 */ 25 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 #include <sys/socket.h> 29 #include <signal.h> 30 #include <locale.h> 31 #include <syslog.h> 32 #include <netdb.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <stdio.h> 38 #include <errno.h> 39 #include <door.h> 40 #include <meta.h> 41 #include <libsysevent.h> 42 #include <wait.h> 43 #include <semaphore.h> 44 #include <libscf.h> 45 46 #include <sys/scsi/adapters/iscsi_door.h> 47 #include <sys/scsi/adapters/iscsi_if.h> 48 49 /* 50 * Local Defines 51 * ------------- 52 */ 53 #define ISCSI_DOOR_DAEMON_SYSLOG_PP "iscsid" 54 #define ISCSI_DISCOVERY_POLL_DELAY1 1 /* Seconds */ 55 #define ISCSI_DISCOVERY_POLL_DELAY2 60 /* Seconds */ 56 #define ISCSI_SMF_OFFLINE_DELAY 10 /* Seconds */ 57 #define ISCSI_SMF_OFFLINE_MAX_RETRY_TIMES 60 58 59 #if !defined(SMF_EXIT_ERR_OTHER) 60 #define SMF_EXIT_ERR_OTHER -1 61 #endif 62 63 /* 64 * Global Variables related to the synchronization of the child process 65 * -------------------------------------------------------------------- 66 */ 67 static pid_t iscsi_child_pid; 68 static sem_t iscsi_child_sem; 69 static int iscsi_child_door_handle; 70 static int iscsi_child_smf_exit_code; 71 72 /* 73 * Global Variables related to the door accessed by the kernel 74 * ----------------------------------------------------------- 75 */ 76 static int iscsi_dev_handle; 77 static int iscsi_kernel_door_handle; 78 79 /* 80 * Prototypes of Functions the body of which is defined farther down 81 * in this file. 82 * ----------------------------------------------------------------- 83 */ 84 static void call_child_door(int value); 85 static void sigchld_handler(int sig); 86 static boolean_t discovery_event_wait(int did); 87 static void signone(int, siginfo_t *, void *); 88 89 static 90 void 91 iscsi_child_door( 92 void *cookie, 93 char *args, 94 size_t alen, 95 door_desc_t *ddp, 96 uint_t ndid 97 ); 98 99 static 100 void 101 iscsi_kernel_door( 102 void *cookie, 103 char *args, 104 size_t alen, 105 door_desc_t *ddp, 106 uint_t ndid 107 ); 108 109 static 110 iscsi_door_cnf_t * 111 _getipnodebyname_req( 112 getipnodebyname_req_t *req, 113 int req_len, 114 size_t *pcnf_len 115 ); 116 117 /* 118 * main -- Entry point of the iSCSI door server daemon 119 * 120 * This function forks, waits for the child process feedback and exits. 121 */ 122 /* ARGSUSED */ 123 int 124 main( 125 int argc, 126 char *argv[] 127 ) 128 { 129 int i; 130 int sig; 131 int ret = -1; 132 int retry = 0; 133 sigset_t sigs, allsigs; 134 struct sigaction act; 135 uint32_t rval; 136 137 /* 138 * Get the locale set up before calling any other routines 139 * with messages to ouput. 140 */ 141 (void) setlocale(LC_ALL, ""); 142 openlog("ISCSI_DOOR_DAEMON_SYSLOG_PP", LOG_PID, LOG_DAEMON); 143 144 /* The child semaphore is created. */ 145 if (sem_init(&iscsi_child_sem, 0, 0) == -1) { 146 exit(SMF_EXIT_ERR_OTHER); 147 } 148 149 /* The door for the child is created. */ 150 iscsi_child_door_handle = door_create(iscsi_child_door, NULL, 0); 151 if (iscsi_child_door_handle == -1) { 152 (void) sem_destroy(&iscsi_child_sem); 153 exit(SMF_EXIT_ERR_OTHER); 154 } 155 156 /* A signal handler is set for SIGCHLD. */ 157 (void) signal(SIGCHLD, sigchld_handler); 158 159 /* 160 * Here begins the daemonizing code 161 * -------------------------------- 162 */ 163 iscsi_child_pid = fork(); 164 if (iscsi_child_pid < 0) { 165 /* The fork failed. */ 166 syslog(LOG_DAEMON | LOG_ERR, gettext("Cannot fork")); 167 (void) sem_destroy(&iscsi_child_sem); 168 exit(SMF_EXIT_ERR_OTHER); 169 } 170 171 if (iscsi_child_pid) { 172 /* 173 * The parent exits after the child has provided feedback. This 174 * waiting phase is to meet one of greenline's requirements. 175 * We shouldn't return till we are sure the service is ready to 176 * be provided. 177 */ 178 (void) sem_wait(&iscsi_child_sem); 179 (void) sem_destroy(&iscsi_child_sem); 180 exit(iscsi_child_smf_exit_code); 181 } 182 183 /* 184 * stdout and stderr are redirected to "/dev/null". 185 */ 186 i = open("/dev/null", O_RDWR); 187 (void) dup2(i, 1); 188 (void) dup2(i, 2); 189 190 /* 191 * Here ends the daemonizing code 192 * ------------------------------ 193 */ 194 195 /* 196 * Block out all signals 197 */ 198 (void) sigfillset(&allsigs); 199 (void) pthread_sigmask(SIG_BLOCK, &allsigs, NULL); 200 201 /* setup the door handle */ 202 iscsi_kernel_door_handle = door_create(iscsi_kernel_door, NULL, 0); 203 if (iscsi_kernel_door_handle == -1) { 204 perror(gettext("door_create failed")); 205 syslog(LOG_DAEMON | LOG_ERR, gettext("door_create failed")); 206 exit(SMF_EXIT_ERR_OTHER); 207 } 208 209 /* 210 * The iSCSI driver is opened. 211 */ 212 iscsi_dev_handle = open(ISCSI_DRIVER_DEVCTL, O_RDWR); 213 if (iscsi_dev_handle == -1) { 214 /* The driver couldn't be opened. */ 215 perror(gettext("iscsi device open failed")); 216 exit(SMF_EXIT_ERR_OTHER); 217 } 218 219 if (ioctl( 220 iscsi_dev_handle, 221 ISCSI_SMF_ONLINE, 222 &iscsi_kernel_door_handle) == -1) { 223 (void) close(iscsi_dev_handle); 224 perror(gettext("ioctl: enable iscsi initiator")); 225 exit(SMF_EXIT_ERR_OTHER); 226 } 227 228 /* 229 * Keep the dev open, so to keep iscsi module from unloaded. 230 * This is crutial to guarantee the consistency of the 231 * door_handle and service state in kernel. 232 */ 233 234 /* We have to wait for the discovery process to finish. */ 235 (void) discovery_event_wait(iscsi_dev_handle); 236 237 /* We let the parent know that everything is ok. */ 238 call_child_door(SMF_EXIT_OK); 239 240 /* now set up signals we care about */ 241 242 (void) sigemptyset(&sigs); 243 (void) sigaddset(&sigs, SIGTERM); 244 (void) sigaddset(&sigs, SIGINT); 245 (void) sigaddset(&sigs, SIGQUIT); 246 247 /* make sure signals to be enqueued */ 248 act.sa_flags = SA_SIGINFO; 249 act.sa_sigaction = signone; 250 251 (void) sigaction(SIGTERM, &act, NULL); 252 (void) sigaction(SIGINT, &act, NULL); 253 (void) sigaction(SIGQUIT, &act, NULL); 254 255 /* wait and process signals */ 256 for (;;) { 257 sig = sigwait(&sigs); 258 if (sig < 0) 259 continue; 260 switch (sig) { 261 case SIGQUIT: 262 case SIGINT: 263 case SIGTERM: 264 do { 265 ret = ioctl(iscsi_dev_handle, 266 ISCSI_SMF_OFFLINE, &rval); 267 if (ret == -1) { 268 /* 269 * Keep retrying if unable 270 * to stop 271 */ 272 (void) sleep(ISCSI_SMF_OFFLINE_DELAY); 273 retry++; 274 } 275 } while ((ret == -1) && 276 (retry < ISCSI_SMF_OFFLINE_MAX_RETRY_TIMES)); 277 (void) close(iscsi_dev_handle); 278 if (rval == B_FALSE) { 279 syslog(LOG_DAEMON, gettext("iSCSI initiator" 280 " service exited with sessions left.")); 281 } 282 return (0); 283 break; 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