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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
27 #include <sys/types.h>
29 #include <sys/socket.h>
41 #include <libsysevent.h>
43 #include <semaphore.h>
46 #include <sys/scsi/adapters/iscsi_door.h>
47 #include <sys/scsi/adapters/iscsi_if.h>
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
59 #if !defined(SMF_EXIT_ERR_OTHER)
60 #define SMF_EXIT_ERR_OTHER -1
64 * Global Variables related to the synchronization of the child process
65 * --------------------------------------------------------------------
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
;
73 * Global Variables related to the door accessed by the kernel
74 * -----------------------------------------------------------
76 static int iscsi_dev_handle
;
77 static int iscsi_kernel_door_handle
;
80 * Prototypes of Functions the body of which is defined farther down
82 * -----------------------------------------------------------------
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 *);
111 _getipnodebyname_req(
112 getipnodebyname_req_t
*req
,
118 * main -- Entry point of the iSCSI door server daemon
120 * This function forks, waits for the child process feedback and exits.
133 sigset_t sigs
, allsigs
;
134 struct sigaction act
;
138 * Get the locale set up before calling any other routines
139 * with messages to ouput.
141 (void) setlocale(LC_ALL
, "");
142 openlog("ISCSI_DOOR_DAEMON_SYSLOG_PP", LOG_PID
, LOG_DAEMON
);
144 /* The child semaphore is created. */
145 if (sem_init(&iscsi_child_sem
, 0, 0) == -1) {
146 exit(SMF_EXIT_ERR_OTHER
);
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
);
156 /* A signal handler is set for SIGCHLD. */
157 (void) signal(SIGCHLD
, sigchld_handler
);
160 * Here begins the daemonizing code
161 * --------------------------------
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
);
171 if (iscsi_child_pid
) {
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
178 (void) sem_wait(&iscsi_child_sem
);
179 (void) sem_destroy(&iscsi_child_sem
);
180 exit(iscsi_child_smf_exit_code
);
184 * stdout and stderr are redirected to "/dev/null".
186 i
= open("/dev/null", O_RDWR
);
191 * Here ends the daemonizing code
192 * ------------------------------
196 * Block out all signals
198 (void) sigfillset(&allsigs
);
199 (void) pthread_sigmask(SIG_BLOCK
, &allsigs
, NULL
);
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
);
210 * The iSCSI driver is opened.
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
);
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
);
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.
234 /* We have to wait for the discovery process to finish. */
235 (void) discovery_event_wait(iscsi_dev_handle
);
237 /* We let the parent know that everything is ok. */
238 call_child_door(SMF_EXIT_OK
);
240 /* now set up signals we care about */
242 (void) sigemptyset(&sigs
);
243 (void) sigaddset(&sigs
, SIGTERM
);
244 (void) sigaddset(&sigs
, SIGINT
);
245 (void) sigaddset(&sigs
, SIGQUIT
);
247 /* make sure signals to be enqueued */
248 act
.sa_flags
= SA_SIGINFO
;
249 act
.sa_sigaction
= signone
;
251 (void) sigaction(SIGTERM
, &act
, NULL
);
252 (void) sigaction(SIGINT
, &act
, NULL
);
253 (void) sigaction(SIGQUIT
, &act
, NULL
);
255 /* wait and process signals */
257 sig
= sigwait(&sigs
);
265 ret
= ioctl(iscsi_dev_handle
,
266 ISCSI_SMF_OFFLINE
, &rval
);
269 * Keep retrying if unable
272 (void) sleep(ISCSI_SMF_OFFLINE_DELAY
);
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."));
290 * sigchld_handler -- SIGCHLD Handler
303 /* This is the default code. */
304 iscsi_child_smf_exit_code
= SMF_EXIT_ERR_OTHER
;
306 ret_pid
= waitpid(iscsi_child_pid
, &status
, WNOHANG
);
308 if (ret_pid
== iscsi_child_pid
) {
309 if (WIFEXITED(status
)) {
310 iscsi_child_smf_exit_code
= WEXITSTATUS(status
);
313 (void) sem_post(&iscsi_child_sem
);
317 * iscsi_child_door -- Child process door entry point
319 * This function is executed when a driver calls door_ki_upcall().
332 int *ptr
= (int *)args
;
334 iscsi_child_smf_exit_code
= SMF_EXIT_ERR_OTHER
;
336 if (alen
>= sizeof (iscsi_child_smf_exit_code
)) {
337 iscsi_child_smf_exit_code
= *ptr
;
339 (void) sem_post(&iscsi_child_sem
);
340 (void) door_return(NULL
, 0, NULL
, 0);
344 * iscsi_kernel_door -- Kernel door entry point
346 * This function is executed when a driver calls door_ki_upcall().
359 iscsi_door_msg_hdr_t err_ind
;
360 iscsi_door_req_t
*req
;
361 iscsi_door_cnf_t
*cnf
;
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
;
371 req
= (iscsi_door_req_t
*)args
;
372 cnf
= (iscsi_door_cnf_t
*)&err_ind
;
373 cnf_len
= sizeof (err_ind
);
376 * The validity of the request is checked before going any farther.
380 * A request has to be passed.
382 err_ind
.status
= ISCSI_DOOR_STATUS_REQ_INVALID
;
383 } else if (alen
< sizeof (iscsi_door_msg_hdr_t
)) {
385 * The buffer containing the request must be at least as big
388 err_ind
.status
= ISCSI_DOOR_STATUS_REQ_LENGTH
;
389 } else if (req
->hdr
.signature
!= ISCSI_DOOR_REQ_SIGNATURE
) {
391 * The request must be correctly signed.
393 err_ind
.status
= ISCSI_DOOR_STATUS_REQ_INVALID
;
394 } else if (req
->hdr
.version
!= ISCSI_DOOR_REQ_VERSION_1
) {
396 * The version of the request must be supported by the server.
398 err_ind
.status
= ISCSI_DOOR_STATUS_REQ_VERSION
;
401 * The request is treated according to the opcode.
403 switch (req
->hdr
.opcode
) {
405 case ISCSI_DOOR_GETIPNODEBYNAME_REQ
:
406 cnf
= _getipnodebyname_req(
412 err_ind
.status
= ISCSI_DOOR_STATUS_REQ_INVALID
;
416 err_code
= door_return((char *)cnf
, cnf_len
, NULL
, 0);
435 (void) fprintf(stderr
, "door_return error(%s,%d)", err_txt
, err_code
);
437 LOG_DAEMON
| LOG_ERR
,
438 gettext("!door_return error(%s,%d)"),
444 * _getipnodebyname_req
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().
453 _getipnodebyname_req(
454 getipnodebyname_req_t
*req
,
458 getipnodebyname_cnf_t
*cnf
= (getipnodebyname_cnf_t
*)req
;
460 struct hostent
*hptr
;
463 /* The opcode is changed immediately. */
464 cnf
->hdr
.opcode
= ISCSI_DOOR_GETIPNODEBYNAME_CNF
;
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
;
470 return ((iscsi_door_cnf_t
*)cnf
);
473 name
= (char *)req
+ req
->name_offset
;
476 * The pointer to the name has to stay inside the request but
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
;
483 return ((iscsi_door_cnf_t
*)cnf
);
486 /* The library function is called. */
487 hptr
= getipnodebyname(
491 (int *)&cnf
->error_num
);
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.
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;
504 cnf
->h_name_offset
= 0;
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
);
510 if (*hptr
->h_addr_list
!= NULL
) {
512 ((char *)cnf
+ sizeof (getipnodebyname_cnf_t
)),
515 cnf
->h_addr_list_length
= 1;
516 cnf
->h_size_needed
+= cnf
->h_addrlen
;
517 cnf_len
+= hptr
->h_length
;
519 cnf
->h_addr_list_length
= 0;
520 cnf
->h_size_needed
+= hptr
->h_length
;
523 cnf
->hdr
.status
= ISCSI_DOOR_STATUS_SUCCESS
;
526 cnf
->hdr
.status
= ISCSI_DOOR_STATUS_SUCCESS
;
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
);
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
);
538 return ((iscsi_door_cnf_t
*)cnf
);
542 * call_child_door -- This function calls the child door with the value
543 * provided by the caller.
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
);
569 iscsi_lun_list_t
*lun_list
;
570 iscsi_lun_list_t
*tmp
;
574 lun_list
= (iscsi_lun_list_t
*)malloc(sizeof (*lun_list
));
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
;
585 ISCSI_LUN_OID_LIST_GET
,
588 /* The Ioctl didn't go well. */
591 if (lun_list
->ll_in_cnt
>= lun_list
->ll_out_cnt
) {
596 * We didn't get all the targets. Let's build a new Ioctl with
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
) {
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
;
614 lun_count
= lun_list
->ll_out_cnt
;
620 * discovery_event_wait -- Waits for the discovery process to finish.
625 discovery_event_wait(
633 iSCSIDiscoveryMethod_t discovery_flags
;
634 iSCSIDiscoveryMethod_t discovery_all
;
640 discovery_all
= iSCSIDiscoveryMethodStatic
|
641 iSCSIDiscoveryMethodSLP
|
642 iSCSIDiscoveryMethodISNS
|
643 iSCSIDiscoveryMethodSendTargets
;
647 /* The status discovery flags are read. */
650 ISCSI_DISCOVERY_EVENTS
,
651 &discovery_flags
) == -1) {
656 if (discovery_flags
== discovery_all
) {
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
) {
672 (void) sleep(ISCSI_DISCOVERY_POLL_DELAY1
);
673 lun_timer
+= ISCSI_DISCOVERY_POLL_DELAY1
;
680 signone(int sig
, siginfo_t
*sip
, void *utp
)