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
main(int argc,char * argv[])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
sigchld_handler(int sig)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
iscsi_child_door(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)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
iscsi_kernel_door(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)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 *
_getipnodebyname_req(getipnodebyname_req_t * req,int req_len,size_t * pcnf_len)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
call_child_door(int value)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
get_luns_count(int did)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
discovery_event_wait(int did)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
signone(int sig,siginfo_t * sip,void * utp)681 signone(int sig, siginfo_t *sip, void *utp)
682 {
683 }
684