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