xref: /illumos-gate/usr/src/cmd/iscsid/iscsid.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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