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