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