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