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