12654012fSReza Sabdar /*
28c4f9701SJanice Chang  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
32654012fSReza Sabdar  */
42654012fSReza Sabdar 
52654012fSReza Sabdar /*
62654012fSReza Sabdar  * BSD 3 Clause License
72654012fSReza Sabdar  *
82654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
92654012fSReza Sabdar  *
102654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
112654012fSReza Sabdar  * modification, are permitted provided that the following conditions
122654012fSReza Sabdar  * are met:
13*82049ff5SToomas Soome  *	- Redistributions of source code must retain the above copyright
142654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
152654012fSReza Sabdar  *
16*82049ff5SToomas Soome  *	- Redistributions in binary form must reproduce the above copyright
172654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
182654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
192654012fSReza Sabdar  *	  distribution.
202654012fSReza Sabdar  *
212654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
222654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
232654012fSReza Sabdar  *	  products derived from this software without specific prior written
242654012fSReza Sabdar  *	  permission.
252654012fSReza Sabdar  *
262654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
272654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
282654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
292654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
302654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
312654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
322654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
332654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
342654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
352654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
362654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
372654012fSReza Sabdar  */
382654012fSReza Sabdar /* Copyright (c) 2007, The Storage Networking Industry Association. */
392654012fSReza Sabdar /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
409ee94b97SJan Kryl /* Copyright 2014 Nexenta Systems, Inc.  All rights reserved. */
412654012fSReza Sabdar 
422654012fSReza Sabdar #include <sys/ioctl.h>
432654012fSReza Sabdar #include <sys/types.h>
442654012fSReza Sabdar #include <sys/socket.h>
452654012fSReza Sabdar #include <sys/socketvar.h>
462654012fSReza Sabdar #include <netinet/in.h>
472654012fSReza Sabdar #include <arpa/inet.h>
482654012fSReza Sabdar #include <net/if.h>
492654012fSReza Sabdar #include <errno.h>
502654012fSReza Sabdar #include <fcntl.h>
512654012fSReza Sabdar #include <netdb.h>
522654012fSReza Sabdar #include <stdlib.h>
532654012fSReza Sabdar #include <unistd.h>
542654012fSReza Sabdar #include <string.h>
552654012fSReza Sabdar #include "ndmpd_common.h"
562654012fSReza Sabdar #include "ndmpd.h"
572654012fSReza Sabdar #include <sys/mtio.h>
582654012fSReza Sabdar 
592654012fSReza Sabdar /*
602654012fSReza Sabdar  * Maximum mover record size
612654012fSReza Sabdar  */
622654012fSReza Sabdar #define	MAX_MOVER_RECSIZE	(512*KILOBYTE)
632654012fSReza Sabdar 
642654012fSReza Sabdar static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
652654012fSReza Sabdar     ushort_t *port);
662654012fSReza Sabdar static int tape_read(ndmpd_session_t *session, char *data);
672654012fSReza Sabdar static int change_tape(ndmpd_session_t *session);
682654012fSReza Sabdar static int discard_data(ndmpd_session_t *session, ulong_t length);
692654012fSReza Sabdar static int mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf);
702654012fSReza Sabdar static int mover_socket_write_one_buf(ndmpd_session_t *session,
712654012fSReza Sabdar     tlm_buffer_t *buf);
722654012fSReza Sabdar static int start_mover_for_restore(ndmpd_session_t *session);
732654012fSReza Sabdar static int mover_socket_read_one_buf(ndmpd_session_t *session,
742654012fSReza Sabdar     tlm_buffer_t *buf, long read_size);
752654012fSReza Sabdar static int mover_tape_write_one_buf(ndmpd_session_t *session,
762654012fSReza Sabdar     tlm_buffer_t *buf);
772654012fSReza Sabdar static int start_mover_for_backup(ndmpd_session_t *session);
782654012fSReza Sabdar static boolean_t is_writer_running_v3(ndmpd_session_t *session);
792654012fSReza Sabdar static int mover_pause_v3(ndmpd_session_t *session,
802654012fSReza Sabdar     ndmp_mover_pause_reason reason);
812654012fSReza Sabdar static int mover_tape_write_v3(ndmpd_session_t *session, char *data,
822654012fSReza Sabdar     ssize_t length);
832654012fSReza Sabdar static int mover_tape_flush_v3(ndmpd_session_t *session);
842654012fSReza Sabdar static int mover_tape_read_v3(ndmpd_session_t *session, char *data);
852654012fSReza Sabdar static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
862654012fSReza Sabdar     ushort_t *port);
872654012fSReza Sabdar static void mover_data_read_v3(void *cookie, int fd, ulong_t mode);
882654012fSReza Sabdar static void accept_connection(void *cookie, int fd, ulong_t mode);
892654012fSReza Sabdar static void mover_data_write_v3(void *cookie, int fd, ulong_t mode);
902654012fSReza Sabdar static void accept_connection_v3(void *cookie, int fd, ulong_t mode);
9197f7c475SJan Kryl static ndmp_error mover_connect_sock(ndmpd_session_t *session,
922654012fSReza Sabdar     ndmp_mover_mode mode, ulong_t addr, ushort_t port);
932654012fSReza Sabdar static boolean_t is_writer_running(ndmpd_session_t *session);
9497f7c475SJan Kryl static int set_socket_nonblock(int sock);
952654012fSReza Sabdar 
962654012fSReza Sabdar 
972654012fSReza Sabdar int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
982654012fSReza Sabdar 
992654012fSReza Sabdar #define	TAPE_READ_ERR		-1
1002654012fSReza Sabdar #define	TAPE_NO_WRITER_ERR	-2
1012654012fSReza Sabdar 
10297f7c475SJan Kryl /*
10397f7c475SJan Kryl  * Set non-blocking mode for socket.
10497f7c475SJan Kryl  */
10597f7c475SJan Kryl static int
set_socket_nonblock(int sock)10697f7c475SJan Kryl set_socket_nonblock(int sock)
10797f7c475SJan Kryl {
10897f7c475SJan Kryl 	int flags;
10997f7c475SJan Kryl 
11097f7c475SJan Kryl 	flags = fcntl(sock, F_GETFL, 0);
11197f7c475SJan Kryl 	if (flags < 0)
11297f7c475SJan Kryl 		return (0);
11397f7c475SJan Kryl 	return (fcntl(sock, F_SETFL, flags|O_NONBLOCK) == 0);
11497f7c475SJan Kryl }
11597f7c475SJan Kryl 
1162654012fSReza Sabdar /*
1172654012fSReza Sabdar  * ************************************************************************
1182654012fSReza Sabdar  * NDMP V2 HANDLERS
1192654012fSReza Sabdar  * ************************************************************************
1202654012fSReza Sabdar  */
1212654012fSReza Sabdar 
1222654012fSReza Sabdar /*
1232654012fSReza Sabdar  * ndmpd_mover_get_state_v2
1242654012fSReza Sabdar  *
1252654012fSReza Sabdar  * This handler handles the mover_get_state request.
1262654012fSReza Sabdar  * Status information for the mover state machine is returned.
1272654012fSReza Sabdar  *
1282654012fSReza Sabdar  * Parameters:
1292654012fSReza Sabdar  *   connection (input) - connection handle.
1302654012fSReza Sabdar  *   body       (input) - request message body.
1312654012fSReza Sabdar  *
1322654012fSReza Sabdar  * Returns:
1332654012fSReza Sabdar  *   void
1342654012fSReza Sabdar  */
1352654012fSReza Sabdar /*ARGSUSED*/
1362654012fSReza Sabdar void
ndmpd_mover_get_state_v2(ndmp_connection_t * connection,void * body)1372654012fSReza Sabdar ndmpd_mover_get_state_v2(ndmp_connection_t *connection, void *body)
1382654012fSReza Sabdar {
1392654012fSReza Sabdar 	ndmp_mover_get_state_reply_v2 reply;
1402654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1412654012fSReza Sabdar 
1422654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
1432654012fSReza Sabdar 	reply.state = session->ns_mover.md_state;
1442654012fSReza Sabdar 	reply.pause_reason = session->ns_mover.md_pause_reason;
1452654012fSReza Sabdar 	reply.halt_reason = session->ns_mover.md_halt_reason;
1462654012fSReza Sabdar 	reply.record_size = session->ns_mover.md_record_size;
1472654012fSReza Sabdar 	reply.record_num = session->ns_mover.md_record_num;
1482654012fSReza Sabdar 	reply.data_written =
1492654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_data_written);
1502654012fSReza Sabdar 	reply.seek_position =
1512654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_seek_position);
1522654012fSReza Sabdar 	reply.bytes_left_to_read =
1532654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
1542654012fSReza Sabdar 	reply.window_offset =
1552654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_offset);
1562654012fSReza Sabdar 	reply.window_length =
1572654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_length);
1582654012fSReza Sabdar 
1592654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
1602654012fSReza Sabdar 	    "sending tape_get_state reply");
1612654012fSReza Sabdar }
1622654012fSReza Sabdar 
1632654012fSReza Sabdar 
1642654012fSReza Sabdar /*
1652654012fSReza Sabdar  * ndmpd_mover_listen_v2
1662654012fSReza Sabdar  *
1672654012fSReza Sabdar  * This handler handles mover_listen requests.
1682654012fSReza Sabdar  *
1692654012fSReza Sabdar  * Parameters:
1702654012fSReza Sabdar  *   connection (input) - connection handle.
1712654012fSReza Sabdar  *   body       (input) - request message body.
1722654012fSReza Sabdar  *
1732654012fSReza Sabdar  * Returns:
1742654012fSReza Sabdar  *   void
1752654012fSReza Sabdar  */
1762654012fSReza Sabdar void
ndmpd_mover_listen_v2(ndmp_connection_t * connection,void * body)1772654012fSReza Sabdar ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
1782654012fSReza Sabdar {
1792654012fSReza Sabdar 	ndmp_mover_listen_request_v2 *request;
1802654012fSReza Sabdar 	ndmp_mover_listen_reply_v2 reply;
1812654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1822654012fSReza Sabdar 	ulong_t addr;
1832654012fSReza Sabdar 	ushort_t port;
1842654012fSReza Sabdar 
1852654012fSReza Sabdar 	request = (ndmp_mover_listen_request_v2 *)body;
1862654012fSReza Sabdar 
1872654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
1882654012fSReza Sabdar 	    session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1892654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
1902654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1912654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
1922654012fSReza Sabdar 		    "sending mover_listen reply");
1932654012fSReza Sabdar 		return;
1942654012fSReza Sabdar 	}
1952654012fSReza Sabdar 	session->ns_mover.md_mode = request->mode;
1962654012fSReza Sabdar 
1972654012fSReza Sabdar 	if (request->addr_type == NDMP_ADDR_LOCAL) {
1982654012fSReza Sabdar 		reply.mover.addr_type = NDMP_ADDR_LOCAL;
1992654012fSReza Sabdar 	} else {
2002654012fSReza Sabdar 		if (create_listen_socket_v2(session, &addr, &port) < 0) {
2012654012fSReza Sabdar 			reply.error = NDMP_IO_ERR;
2022654012fSReza Sabdar 			ndmp_send_reply(connection, (void *) &reply,
2032654012fSReza Sabdar 			    "sending mover_listen reply");
2042654012fSReza Sabdar 			return;
2052654012fSReza Sabdar 		}
2062654012fSReza Sabdar 		reply.mover.addr_type = NDMP_ADDR_TCP;
2072654012fSReza Sabdar 		reply.mover.ndmp_mover_addr_u.addr.ip_addr = htonl(addr);
2082654012fSReza Sabdar 		reply.mover.ndmp_mover_addr_u.addr.port = htons(port);
2092654012fSReza Sabdar 	}
2102654012fSReza Sabdar 
2112654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
2122654012fSReza Sabdar 
2132654012fSReza Sabdar 	/*
2142654012fSReza Sabdar 	 * ndmp window should always set by client during restore
2152654012fSReza Sabdar 	 */
2162654012fSReza Sabdar 
2172654012fSReza Sabdar 	/* Set the default window. */
2182654012fSReza Sabdar 	session->ns_mover.md_window_offset = 0;
2192654012fSReza Sabdar 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
2202654012fSReza Sabdar 	session->ns_mover.md_position = 0;
2212654012fSReza Sabdar 
2222654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
2232654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
2242654012fSReza Sabdar 	    "sending mover_listen reply");
2252654012fSReza Sabdar }
2262654012fSReza Sabdar 
2272654012fSReza Sabdar 
2282654012fSReza Sabdar /*
2292654012fSReza Sabdar  * ndmpd_mover_continue_v2
2302654012fSReza Sabdar  *
2312654012fSReza Sabdar  * This handler handles mover_continue requests.
2322654012fSReza Sabdar  *
2332654012fSReza Sabdar  * Parameters:
2342654012fSReza Sabdar  *   connection (input) - connection handle.
2352654012fSReza Sabdar  *   body       (input) - request message body.
2362654012fSReza Sabdar  *
2372654012fSReza Sabdar  * Returns:
2382654012fSReza Sabdar  *   void
2392654012fSReza Sabdar  */
2402654012fSReza Sabdar /*ARGSUSED*/
2412654012fSReza Sabdar void
ndmpd_mover_continue_v2(ndmp_connection_t * connection,void * body)2422654012fSReza Sabdar ndmpd_mover_continue_v2(ndmp_connection_t *connection, void *body)
2432654012fSReza Sabdar {
2442654012fSReza Sabdar 	ndmp_mover_continue_reply reply;
2452654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
2462654012fSReza Sabdar 
2472654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
2482654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
2492654012fSReza Sabdar 
2502654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
2512654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
2522654012fSReza Sabdar 		    "sending mover_continue reply");
2532654012fSReza Sabdar 		return;
2542654012fSReza Sabdar 	}
2552654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2562654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
2572654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
2582654012fSReza Sabdar 	    "sending mover_continue reply");
2592654012fSReza Sabdar }
2602654012fSReza Sabdar 
2612654012fSReza Sabdar 
2622654012fSReza Sabdar /*
2632654012fSReza Sabdar  * ndmpd_mover_abort_v2
2642654012fSReza Sabdar  *
2652654012fSReza Sabdar  * This handler handles mover_abort requests.
2662654012fSReza Sabdar  *
2672654012fSReza Sabdar  * Parameters:
2682654012fSReza Sabdar  *   connection (input) - connection handle.
2692654012fSReza Sabdar  *   body       (input) - request message body.
2702654012fSReza Sabdar  *
2712654012fSReza Sabdar  * Returns:
2722654012fSReza Sabdar  *   void
2732654012fSReza Sabdar  */
2742654012fSReza Sabdar /*ARGSUSED*/
2752654012fSReza Sabdar void
ndmpd_mover_abort_v2(ndmp_connection_t * connection,void * body)2762654012fSReza Sabdar ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
2772654012fSReza Sabdar {
2782654012fSReza Sabdar 	ndmp_mover_abort_reply reply;
2792654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
2802654012fSReza Sabdar 
2812654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
2822654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
2832654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
2842654012fSReza Sabdar 
2852654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
2862654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
2872654012fSReza Sabdar 		    "sending mover_abort reply");
2882654012fSReza Sabdar 		return;
2892654012fSReza Sabdar 	}
2902654012fSReza Sabdar 
2912654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
2922654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
2932654012fSReza Sabdar 	    "sending mover_abort reply");
2942654012fSReza Sabdar 
2952654012fSReza Sabdar 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
2962654012fSReza Sabdar 	ndmp_stop_buffer_worker(session);
2972654012fSReza Sabdar }
2982654012fSReza Sabdar 
2992654012fSReza Sabdar 
3002654012fSReza Sabdar /*
3012654012fSReza Sabdar  * ndmpd_mover_stop_v2
3022654012fSReza Sabdar  *
3032654012fSReza Sabdar  * This handler handles mover_stop requests.
3042654012fSReza Sabdar  *
3052654012fSReza Sabdar  * Parameters:
3062654012fSReza Sabdar  *   connection (input) - connection handle.
3072654012fSReza Sabdar  *   body       (input) - request message body.
3082654012fSReza Sabdar  *
3092654012fSReza Sabdar  * Returns:
3102654012fSReza Sabdar  *   void
3112654012fSReza Sabdar  */
3122654012fSReza Sabdar /*ARGSUSED*/
3132654012fSReza Sabdar void
ndmpd_mover_stop_v2(ndmp_connection_t * connection,void * body)3142654012fSReza Sabdar ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
3152654012fSReza Sabdar {
3162654012fSReza Sabdar 	ndmp_mover_stop_reply reply;
3172654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
3182654012fSReza Sabdar 
3192654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {
3202654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
3212654012fSReza Sabdar 
3222654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
3232654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
3242654012fSReza Sabdar 		    "sending mover_stop reply");
3252654012fSReza Sabdar 		return;
3262654012fSReza Sabdar 	}
3272654012fSReza Sabdar 
3282654012fSReza Sabdar 	ndmp_waitfor_op(session);
3292654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
3302654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
3312654012fSReza Sabdar 	    "sending mover_stop reply");
3322654012fSReza Sabdar 
3332654012fSReza Sabdar 	ndmp_lbr_cleanup(session);
3342654012fSReza Sabdar 	ndmpd_mover_cleanup(session);
3352654012fSReza Sabdar 	(void) ndmpd_mover_init(session);
3362654012fSReza Sabdar 	(void) ndmp_lbr_init(session);
3372654012fSReza Sabdar }
3382654012fSReza Sabdar 
3392654012fSReza Sabdar 
3402654012fSReza Sabdar /*
3412654012fSReza Sabdar  * ndmpd_mover_set_window_v2
3422654012fSReza Sabdar  *
3432654012fSReza Sabdar  * This handler handles mover_set_window requests.
3442654012fSReza Sabdar  *
3452654012fSReza Sabdar  *
3462654012fSReza Sabdar  * Parameters:
3472654012fSReza Sabdar  *   connection (input) - connection handle.
3482654012fSReza Sabdar  *   body       (input) - request message body.
3492654012fSReza Sabdar  *
3502654012fSReza Sabdar  * Returns:
3512654012fSReza Sabdar  *   void
3522654012fSReza Sabdar  */
3532654012fSReza Sabdar void
ndmpd_mover_set_window_v2(ndmp_connection_t * connection,void * body)3542654012fSReza Sabdar ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
3552654012fSReza Sabdar {
3562654012fSReza Sabdar 	ndmp_mover_set_window_request *request;
3572654012fSReza Sabdar 	ndmp_mover_set_window_reply reply;
3582654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
3592654012fSReza Sabdar 
3602654012fSReza Sabdar 	request = (ndmp_mover_set_window_request *) body;
3612654012fSReza Sabdar 
3622654012fSReza Sabdar 	/*
3632654012fSReza Sabdar 	 * The NDMPv2 specification states that "a window can be set only
3642654012fSReza Sabdar 	 * when in the listen or paused state."
3652654012fSReza Sabdar 	 *
3662654012fSReza Sabdar 	 * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
3672654012fSReza Sabdar 	 * allowing it in the idle state as well.
3682654012fSReza Sabdar 	 */
3692654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
3702654012fSReza Sabdar 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
3712654012fSReza Sabdar 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
3722654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
3732654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
3742654012fSReza Sabdar 		    session->ns_mover.md_state);
3752654012fSReza Sabdar 	} else {
3762654012fSReza Sabdar 		if (quad_to_long_long(request->length) == 0) {
3772654012fSReza Sabdar 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
3782654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
3792654012fSReza Sabdar 			    quad_to_long_long(request->length));
3802654012fSReza Sabdar 		} else {
3812654012fSReza Sabdar 			reply.error = NDMP_NO_ERR;
3822654012fSReza Sabdar 			session->ns_mover.md_window_offset =
3832654012fSReza Sabdar 			    quad_to_long_long(request->offset);
3842654012fSReza Sabdar 			session->ns_mover.md_window_length =
3852654012fSReza Sabdar 			    quad_to_long_long(request->length);
3862654012fSReza Sabdar 			session->ns_mover.md_position =
3872654012fSReza Sabdar 			    session->ns_mover.md_window_offset;
3882654012fSReza Sabdar 		}
3892654012fSReza Sabdar 	}
3902654012fSReza Sabdar 
3912654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
3922654012fSReza Sabdar 	    "sending mover_set_window reply");
3932654012fSReza Sabdar }
3942654012fSReza Sabdar 
3952654012fSReza Sabdar 
3962654012fSReza Sabdar /*
3972654012fSReza Sabdar  * ndmpd_mover_read_v2
3982654012fSReza Sabdar  *
3992654012fSReza Sabdar  * This handler handles mover_read requests. If the requested offset is
4002654012fSReza Sabdar  * outside of the current window, the mover is paused and a notify_mover_paused
4012654012fSReza Sabdar  * request is sent notifying the client that a seek is required. If the
4022654012fSReza Sabdar  * requested offest is within the window but not within the current record,
4032654012fSReza Sabdar  * then the tape is positioned to the record containing the requested offest.
4042654012fSReza Sabdar  * The requested amount of data is then read from the tape device and written
4052654012fSReza Sabdar  * to the data connection.
4062654012fSReza Sabdar  *
4072654012fSReza Sabdar  * Parameters:
4082654012fSReza Sabdar  *   connection (input) - connection handle.
4092654012fSReza Sabdar  *   body       (input) - request message body.
4102654012fSReza Sabdar  *
4112654012fSReza Sabdar  * Returns:
4122654012fSReza Sabdar  *   void
4132654012fSReza Sabdar  */
4142654012fSReza Sabdar void
ndmpd_mover_read_v2(ndmp_connection_t * connection,void * body)4152654012fSReza Sabdar ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
4162654012fSReza Sabdar {
4172654012fSReza Sabdar 	ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
4182654012fSReza Sabdar 	ndmp_mover_read_reply reply;
4192654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
4202654012fSReza Sabdar 	int err;
4212654012fSReza Sabdar 
4222654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
4232654012fSReza Sabdar 	    session->ns_mover.md_bytes_left_to_read != 0 ||
4242654012fSReza Sabdar 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
4252654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
4262654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
4272654012fSReza Sabdar 		ndmp_send_reply(connection, &reply,
4282654012fSReza Sabdar 		    "sending mover_read reply");
4292654012fSReza Sabdar 		return;
4302654012fSReza Sabdar 	}
4312654012fSReza Sabdar 	if (session->ns_tape.td_fd == -1) {
4322654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
4332654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
4342654012fSReza Sabdar 		ndmp_send_reply(connection, &reply,
4352654012fSReza Sabdar 		    "sending mover_read reply");
4362654012fSReza Sabdar 		return;
4372654012fSReza Sabdar 	}
4382654012fSReza Sabdar 
4392654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
4402654012fSReza Sabdar 	ndmp_send_reply(connection, &reply, "sending mover_read reply");
4412654012fSReza Sabdar 
4422654012fSReza Sabdar 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
4432654012fSReza Sabdar 	    quad_to_long_long(request->length));
4442654012fSReza Sabdar 	if (err < 0) {
4452654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4462654012fSReza Sabdar 		return;
4472654012fSReza Sabdar 	}
4482654012fSReza Sabdar 	/*
4492654012fSReza Sabdar 	 * Just return if we are waiting for the NDMP client to
4502654012fSReza Sabdar 	 * complete the seek.
4512654012fSReza Sabdar 	 */
4522654012fSReza Sabdar 	if (err == 1)
4532654012fSReza Sabdar 		return;
4542654012fSReza Sabdar 
4552654012fSReza Sabdar 	/*
4562654012fSReza Sabdar 	 * Start the mover for restore in the 3-way backups.
4572654012fSReza Sabdar 	 */
4582654012fSReza Sabdar 	if (start_mover_for_restore(session) < 0)
4592654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4602654012fSReza Sabdar }
4612654012fSReza Sabdar 
4622654012fSReza Sabdar 
4632654012fSReza Sabdar /*
4642654012fSReza Sabdar  * ndmpd_mover_close_v2
4652654012fSReza Sabdar  *
4662654012fSReza Sabdar  * This handler handles mover_close requests.
4672654012fSReza Sabdar  *
4682654012fSReza Sabdar  * Parameters:
4692654012fSReza Sabdar  *   connection (input) - connection handle.
4702654012fSReza Sabdar  *   body       (input) - request message body.
4712654012fSReza Sabdar  *
4722654012fSReza Sabdar  * Returns:
4732654012fSReza Sabdar  *   void
4742654012fSReza Sabdar  */
4752654012fSReza Sabdar /*ARGSUSED*/
4762654012fSReza Sabdar void
ndmpd_mover_close_v2(ndmp_connection_t * connection,void * body)4772654012fSReza Sabdar ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
4782654012fSReza Sabdar {
4792654012fSReza Sabdar 	ndmp_mover_close_reply reply;
4802654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
4812654012fSReza Sabdar 
4822654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
4832654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
4842654012fSReza Sabdar 
4852654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
4862654012fSReza Sabdar 		ndmp_send_reply(connection, &reply,
4872654012fSReza Sabdar 		    "sending mover_close reply");
4882654012fSReza Sabdar 		return;
4892654012fSReza Sabdar 	}
4902654012fSReza Sabdar 	free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
4912654012fSReza Sabdar 
4922654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
4932654012fSReza Sabdar 	ndmp_send_reply(connection, &reply, "sending mover_close reply");
4942654012fSReza Sabdar 
4952654012fSReza Sabdar 	ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
4962654012fSReza Sabdar }
4972654012fSReza Sabdar 
4982654012fSReza Sabdar 
4992654012fSReza Sabdar /*
5002654012fSReza Sabdar  * ndmpd_mover_set_record_size_v2
5012654012fSReza Sabdar  *
5022654012fSReza Sabdar  * This handler handles mover_set_record_size requests.
5032654012fSReza Sabdar  *
5042654012fSReza Sabdar  * Parameters:
5052654012fSReza Sabdar  *   connection (input) - connection handle.
5062654012fSReza Sabdar  *   body       (input) - request message body.
5072654012fSReza Sabdar  *
5082654012fSReza Sabdar  * Returns:
5092654012fSReza Sabdar  *   void
5102654012fSReza Sabdar  */
5112654012fSReza Sabdar void
ndmpd_mover_set_record_size_v2(ndmp_connection_t * connection,void * body)5122654012fSReza Sabdar ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
5132654012fSReza Sabdar {
5142654012fSReza Sabdar 	ndmp_mover_set_record_size_request *request;
5152654012fSReza Sabdar 	ndmp_mover_set_record_size_reply reply;
5162654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
5172654012fSReza Sabdar 
5182654012fSReza Sabdar 	request = (ndmp_mover_set_record_size_request *) body;
5192654012fSReza Sabdar 
5202654012fSReza Sabdar 	session->ns_mover.md_record_size = request->len;
5212654012fSReza Sabdar 	session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
5222654012fSReza Sabdar 	    request->len);
5232654012fSReza Sabdar 
5242654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
5252654012fSReza Sabdar 	ndmp_send_reply(connection, &reply,
5262654012fSReza Sabdar 	    "sending mover_set_record_size reply");
5272654012fSReza Sabdar }
5282654012fSReza Sabdar 
5292654012fSReza Sabdar 
5302654012fSReza Sabdar /*
5312654012fSReza Sabdar  * ************************************************************************
5322654012fSReza Sabdar  * NDMP V3 HANDLERS
5332654012fSReza Sabdar  * ************************************************************************
5342654012fSReza Sabdar  */
5352654012fSReza Sabdar 
5362654012fSReza Sabdar /*
5372654012fSReza Sabdar  * ndmpd_mover_get_state_v3
5382654012fSReza Sabdar  *
5392654012fSReza Sabdar  * This handler handles the ndmp_mover_get_state_request.
5402654012fSReza Sabdar  * Status information for the mover state machine is returned.
5412654012fSReza Sabdar  *
5422654012fSReza Sabdar  * Parameters:
5432654012fSReza Sabdar  *   connection (input) - connection handle.
5442654012fSReza Sabdar  *   body       (input) - request message body.
5452654012fSReza Sabdar  *
5462654012fSReza Sabdar  * Returns:
5472654012fSReza Sabdar  *   void
5482654012fSReza Sabdar  */
5492654012fSReza Sabdar /*ARGSUSED*/
5502654012fSReza Sabdar void
ndmpd_mover_get_state_v3(ndmp_connection_t * connection,void * body)5512654012fSReza Sabdar ndmpd_mover_get_state_v3(ndmp_connection_t *connection, void *body)
5522654012fSReza Sabdar {
5532654012fSReza Sabdar 	ndmp_mover_get_state_reply_v3 reply;
5542654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
5552654012fSReza Sabdar 
5562654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
5572654012fSReza Sabdar 
5582654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
5592654012fSReza Sabdar 	reply.state = session->ns_mover.md_state;
5602654012fSReza Sabdar 	reply.pause_reason = session->ns_mover.md_pause_reason;
5612654012fSReza Sabdar 	reply.halt_reason = session->ns_mover.md_halt_reason;
5622654012fSReza Sabdar 	reply.record_size = session->ns_mover.md_record_size;
5632654012fSReza Sabdar 	reply.record_num = session->ns_mover.md_record_num;
5642654012fSReza Sabdar 	reply.data_written =
5652654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_data_written);
5662654012fSReza Sabdar 	reply.seek_position =
5672654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_seek_position);
5682654012fSReza Sabdar 	reply.bytes_left_to_read =
5692654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
5702654012fSReza Sabdar 	reply.window_offset =
5712654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_offset);
5722654012fSReza Sabdar 	reply.window_length =
5732654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_length);
5742654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
5752654012fSReza Sabdar 		ndmp_copy_addr_v3(&reply.data_connection_addr,
5762654012fSReza Sabdar 		    &session->ns_mover.md_data_addr);
5772654012fSReza Sabdar 
5782654012fSReza Sabdar 	ndmp_send_reply(connection, &reply,
5792654012fSReza Sabdar 	    "sending ndmp_mover_get_state reply");
5802654012fSReza Sabdar }
5812654012fSReza Sabdar 
5822654012fSReza Sabdar 
5832654012fSReza Sabdar /*
5842654012fSReza Sabdar  * ndmpd_mover_listen_v3
5852654012fSReza Sabdar  *
5862654012fSReza Sabdar  * This handler handles ndmp_mover_listen_requests.
5872654012fSReza Sabdar  * A TCP/IP socket is created that is used to listen for
5882654012fSReza Sabdar  * and accept data connections initiated by a remote
5892654012fSReza Sabdar  * data server.
5902654012fSReza Sabdar  *
5912654012fSReza Sabdar  * Parameters:
5922654012fSReza Sabdar  *   connection (input) - connection handle.
5932654012fSReza Sabdar  *   body       (input) - request message body.
5942654012fSReza Sabdar  *
5952654012fSReza Sabdar  * Returns:
5962654012fSReza Sabdar  *   void
5972654012fSReza Sabdar  */
5982654012fSReza Sabdar void
ndmpd_mover_listen_v3(ndmp_connection_t * connection,void * body)5992654012fSReza Sabdar ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
6002654012fSReza Sabdar {
6012654012fSReza Sabdar 	ndmp_mover_listen_request_v3 *request;
6022654012fSReza Sabdar 	ndmp_mover_listen_reply_v3 reply;
6032654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
6042654012fSReza Sabdar 	ulong_t addr;
6052654012fSReza Sabdar 	ushort_t port;
6062654012fSReza Sabdar 
6072654012fSReza Sabdar 	request = (ndmp_mover_listen_request_v3 *)body;
6082654012fSReza Sabdar 
6092654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
6102654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
6112654012fSReza Sabdar 
6122654012fSReza Sabdar 	if (request->mode != NDMP_MOVER_MODE_READ &&
6132654012fSReza Sabdar 	    request->mode != NDMP_MOVER_MODE_WRITE) {
6142654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6152654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
6162654012fSReza Sabdar 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
6172654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6182654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
6192654012fSReza Sabdar 		    request->addr_type);
6202654012fSReza Sabdar 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
6212654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
6222654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
6232654012fSReza Sabdar 		    "Invalid mover state to process listen request");
6242654012fSReza Sabdar 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
6252654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
6262654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
6272654012fSReza Sabdar 		    "Invalid data state to process listen request");
6282654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
6292654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
6302654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No tape device open");
6312654012fSReza Sabdar 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
6322654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
6332654012fSReza Sabdar 		reply.error = NDMP_PERMISSION_ERR;
6342654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
6352654012fSReza Sabdar 	}
6362654012fSReza Sabdar 
6372654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
6382654012fSReza Sabdar 		ndmp_send_reply(connection, &reply,
6392654012fSReza Sabdar 		    "error sending ndmp_mover_listen reply");
6402654012fSReza Sabdar 		return;
6412654012fSReza Sabdar 	}
6422654012fSReza Sabdar 
6432654012fSReza Sabdar 	switch (request->addr_type) {
6442654012fSReza Sabdar 	case NDMP_ADDR_LOCAL:
6452654012fSReza Sabdar 		reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
6462654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
6472654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
6482654012fSReza Sabdar 		break;
6492654012fSReza Sabdar 	case NDMP_ADDR_TCP:
6502654012fSReza Sabdar 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
6512654012fSReza Sabdar 			reply.error = NDMP_IO_ERR;
6522654012fSReza Sabdar 			break;
6532654012fSReza Sabdar 		}
6542654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
6552654012fSReza Sabdar 		reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
6562654012fSReza Sabdar 		reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
6572654012fSReza Sabdar 		reply.data_connection_addr.tcp_port_v3 = htons(port);
6582654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
6592654012fSReza Sabdar 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
6602654012fSReza Sabdar 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
6612654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
6622654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
6632654012fSReza Sabdar 		break;
6642654012fSReza Sabdar 	default:
6652654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6662654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
6672654012fSReza Sabdar 		    request->addr_type);
6682654012fSReza Sabdar 	}
6692654012fSReza Sabdar 
6702654012fSReza Sabdar 	if (reply.error == NDMP_NO_ERR) {
6712654012fSReza Sabdar 		session->ns_mover.md_mode = request->mode;
6722654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
6732654012fSReza Sabdar 	}
6742654012fSReza Sabdar 
6752654012fSReza Sabdar 	ndmp_send_reply(connection, &reply,
6762654012fSReza Sabdar 	    "error sending ndmp_mover_listen reply");
6772654012fSReza Sabdar }
6782654012fSReza Sabdar 
6792654012fSReza Sabdar 
6802654012fSReza Sabdar /*
6812654012fSReza Sabdar  * ndmpd_mover_continue_v3
6822654012fSReza Sabdar  *
6832654012fSReza Sabdar  * This handler handles ndmp_mover_continue_requests.
6842654012fSReza Sabdar  *
6852654012fSReza Sabdar  * Parameters:
6862654012fSReza Sabdar  *   connection (input) - connection handle.
6872654012fSReza Sabdar  *   body       (input) - request message body.
6882654012fSReza Sabdar  *
6892654012fSReza Sabdar  * Returns:
6902654012fSReza Sabdar  *   void
6912654012fSReza Sabdar  */
6922654012fSReza Sabdar /*ARGSUSED*/
6932654012fSReza Sabdar void
ndmpd_mover_continue_v3(ndmp_connection_t * connection,void * body)6942654012fSReza Sabdar ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
6952654012fSReza Sabdar {
6962654012fSReza Sabdar 	ndmp_mover_continue_reply reply;
6972654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
698a23888a3SJan Kryl 	ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
6992654012fSReza Sabdar 	int ret;
7002654012fSReza Sabdar 
7012654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
7022654012fSReza Sabdar 
7032654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
7042654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
7052654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
7062654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
7072654012fSReza Sabdar 		    "sending mover_continue reply");
7082654012fSReza Sabdar 		return;
7092654012fSReza Sabdar 	}
7102654012fSReza Sabdar 
7112654012fSReza Sabdar 	if (session->ns_protocol_version == NDMPV4 &&
7122654012fSReza Sabdar 	    !session->ns_mover.md_pre_cond) {
7132654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Precondition check");
7142654012fSReza Sabdar 		reply.error = NDMP_PRECONDITION_ERR;
7152654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
7162654012fSReza Sabdar 		    "sending mover_continue reply");
7172654012fSReza Sabdar 		return;
7182654012fSReza Sabdar 	}
7192654012fSReza Sabdar 	/*
7202654012fSReza Sabdar 	 * Restore the file handler if the mover is remote to the data
7212654012fSReza Sabdar 	 * server and the handler was removed pending the continuation of a
7222654012fSReza Sabdar 	 * seek request. The handler is removed in mover_data_write().
7232654012fSReza Sabdar 	 */
7242654012fSReza Sabdar 	if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
7252654012fSReza Sabdar 	    session->ns_mover.md_sock != -1) {
7262654012fSReza Sabdar 		/*
7272654012fSReza Sabdar 		 * If we are here, it means that we needed DMA interference
7282654012fSReza Sabdar 		 * for seek. We should be on the right window, so we do not
7292654012fSReza Sabdar 		 * need the DMA interference anymore.
7302654012fSReza Sabdar 		 * We do another seek inside the Window to move to the
7312654012fSReza Sabdar 		 * exact position on the tape.
7322654012fSReza Sabdar 		 * If the resore is running without DAR the pause reason should
7332654012fSReza Sabdar 		 * not be seek.
7342654012fSReza Sabdar 		 */
7352654012fSReza Sabdar 		ret = ndmpd_mover_seek(session,
7362654012fSReza Sabdar 		    session->ns_mover.md_seek_position,
7372654012fSReza Sabdar 		    session->ns_mover.md_bytes_left_to_read);
7382654012fSReza Sabdar 		if (ret < 0) {
7392654012fSReza Sabdar 			ndmpd_mover_error(session,
7402654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
7412654012fSReza Sabdar 			return;
7422654012fSReza Sabdar 		}
7432654012fSReza Sabdar 
7442654012fSReza Sabdar 		if (!ret) {
7452654012fSReza Sabdar 			if (ndmpd_add_file_handler(session, (void*) session,
7462654012fSReza Sabdar 			    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
7472654012fSReza Sabdar 			    HC_MOVER, mover_data_write_v3) < 0)
7482654012fSReza Sabdar 				ndmpd_mover_error(session,
7492654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
7502654012fSReza Sabdar 		} else {
7512654012fSReza Sabdar 			/*
7522654012fSReza Sabdar 			 * This should not happen because we should be in the
7532654012fSReza Sabdar 			 * right window. This means that DMA does not follow
7542654012fSReza Sabdar 			 * the V3 spec.
7552654012fSReza Sabdar 			 */
7562654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "DMA Error.");
7572654012fSReza Sabdar 			ndmpd_mover_error(session,
7582654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
7592654012fSReza Sabdar 			return;
7602654012fSReza Sabdar 		}
7612654012fSReza Sabdar 	}
7622654012fSReza Sabdar 
763a23888a3SJan Kryl 	(void) mutex_lock(&nlp->nlp_mtx);
7642654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
7652654012fSReza Sabdar 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
766f5b1cef2SJan Kryl 	/* The tape has been likely exchanged, reset tape block counter */
767f5b1cef2SJan Kryl 	session->ns_tape.td_record_count = 0;
768a23888a3SJan Kryl 	(void) cond_broadcast(&nlp->nlp_cv);
769a23888a3SJan Kryl 	(void) mutex_unlock(&nlp->nlp_mtx);
7702654012fSReza Sabdar 
7712654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
7722654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
7732654012fSReza Sabdar 	    "sending mover_continue reply");
7742654012fSReza Sabdar }
7752654012fSReza Sabdar 
7762654012fSReza Sabdar 
7772654012fSReza Sabdar /*
7782654012fSReza Sabdar  * ndmpd_mover_abort_v3
7792654012fSReza Sabdar  *
7802654012fSReza Sabdar  * This handler handles mover_abort requests.
7812654012fSReza Sabdar  *
7822654012fSReza Sabdar  * Parameters:
7832654012fSReza Sabdar  *   connection (input) - connection handle.
7842654012fSReza Sabdar  *   body       (input) - request message body.
7852654012fSReza Sabdar  *
7862654012fSReza Sabdar  * Returns:
7872654012fSReza Sabdar  *   void
7882654012fSReza Sabdar  */
7892654012fSReza Sabdar /*ARGSUSED*/
7902654012fSReza Sabdar void
ndmpd_mover_abort_v3(ndmp_connection_t * connection,void * body)7912654012fSReza Sabdar ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
7922654012fSReza Sabdar {
7932654012fSReza Sabdar 	ndmp_mover_abort_reply reply;
7942654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
7952654012fSReza Sabdar 
7962654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
7972654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
7982654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
7992654012fSReza Sabdar 
8002654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
8012654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
8022654012fSReza Sabdar 		    "sending mover_abort reply");
8032654012fSReza Sabdar 		return;
8042654012fSReza Sabdar 	}
8052654012fSReza Sabdar 
8062654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
8072654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
8082654012fSReza Sabdar 	    "sending mover_abort reply");
8092654012fSReza Sabdar 
8102654012fSReza Sabdar 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
8112654012fSReza Sabdar }
8122654012fSReza Sabdar 
8132654012fSReza Sabdar 
8142654012fSReza Sabdar /*
8152654012fSReza Sabdar  * ndmpd_mover_set_window_v3
8162654012fSReza Sabdar  *
8172654012fSReza Sabdar  * This handler handles mover_set_window requests.
8182654012fSReza Sabdar  *
8192654012fSReza Sabdar  *
8202654012fSReza Sabdar  * Parameters:
8212654012fSReza Sabdar  *   connection (input) - connection handle.
8222654012fSReza Sabdar  *   body       (input) - request message body.
8232654012fSReza Sabdar  *
8242654012fSReza Sabdar  * Returns:
8252654012fSReza Sabdar  *   void
8262654012fSReza Sabdar  */
8272654012fSReza Sabdar void
ndmpd_mover_set_window_v3(ndmp_connection_t * connection,void * body)8282654012fSReza Sabdar ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
8292654012fSReza Sabdar {
8302654012fSReza Sabdar 	ndmp_mover_set_window_request *request;
8312654012fSReza Sabdar 	ndmp_mover_set_window_reply reply;
8322654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
8332654012fSReza Sabdar 
8342654012fSReza Sabdar 	request = (ndmp_mover_set_window_request *) body;
8352654012fSReza Sabdar 
8362654012fSReza Sabdar 	/*
8372654012fSReza Sabdar 	 * Note: The spec says that the window can be set only in the listen
8382654012fSReza Sabdar 	 * and paused states.  We let this happen when mover is in the idle
8392654012fSReza Sabdar 	 * state as well.  I can't rememebr which NDMP client (net_backup 4.5
8402654012fSReza Sabdar 	 * or net_worker 6.1.1) forced us to do this!
8412654012fSReza Sabdar 	 */
8422654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
8432654012fSReza Sabdar 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
8442654012fSReza Sabdar 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
8452654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
8462654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
8472654012fSReza Sabdar 		    session->ns_mover.md_state);
8482654012fSReza Sabdar 	} else if (session->ns_mover.md_record_size == 0) {
8492654012fSReza Sabdar 		if (session->ns_protocol_version == NDMPV4)
8502654012fSReza Sabdar 			reply.error = NDMP_PRECONDITION_ERR;
8512654012fSReza Sabdar 		else
8522654012fSReza Sabdar 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
8532654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
8542654012fSReza Sabdar 	} else
8552654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
8562654012fSReza Sabdar 
8572654012fSReza Sabdar 	if (quad_to_long_long(request->length) == 0) {
8582654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
8592654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
8602654012fSReza Sabdar 		    quad_to_long_long(request->length));
8612654012fSReza Sabdar 	}
8622654012fSReza Sabdar 
8632654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
8642654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
8652654012fSReza Sabdar 		    "sending mover_set_window_v3 reply");
8662654012fSReza Sabdar 		return;
8672654012fSReza Sabdar 	}
8682654012fSReza Sabdar 
8692654012fSReza Sabdar 	session->ns_mover.md_pre_cond = TRUE;
8702654012fSReza Sabdar 	session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
8712654012fSReza Sabdar 	session->ns_mover.md_window_length = quad_to_long_long(request->length);
8722654012fSReza Sabdar 
8732654012fSReza Sabdar 	/*
8742654012fSReza Sabdar 	 * We have to update the position for DAR. DAR needs this
8752654012fSReza Sabdar 	 * information to position to the right index on tape,
8762654012fSReza Sabdar 	 * especially when we span the tapes.
8772654012fSReza Sabdar 	 */
8782654012fSReza Sabdar #ifdef	NO_POSITION_CHANGE
8792654012fSReza Sabdar 	/*
8802654012fSReza Sabdar 	 * Do not change the mover position if we are reading from
8812654012fSReza Sabdar 	 * the tape.  In this way, we can use the position+window_length
8822654012fSReza Sabdar 	 * to know how much we can write to a tape before pausing with
8832654012fSReza Sabdar 	 * EOW reason.
8842654012fSReza Sabdar 	 */
8852654012fSReza Sabdar 	if (session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE)
8862654012fSReza Sabdar #endif	/* NO_POSITION_CHANGE */
8872654012fSReza Sabdar 		session->ns_mover.md_position =
8882654012fSReza Sabdar 		    session->ns_mover.md_window_offset;
8892654012fSReza Sabdar 
8902654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
8912654012fSReza Sabdar 	    "sending mover_set_window_v3 reply");
8922654012fSReza Sabdar }
8932654012fSReza Sabdar 
8942654012fSReza Sabdar 
8952654012fSReza Sabdar /*
8962654012fSReza Sabdar  * ndmpd_mover_read_v3
8972654012fSReza Sabdar  *
8982654012fSReza Sabdar  * This handler handles ndmp_mover_read_requests.
8992654012fSReza Sabdar  * If the requested offset is outside of the current window, the mover
9002654012fSReza Sabdar  * is paused and a notify_mover_paused request is sent notifying the
9012654012fSReza Sabdar  * client that a seek is required. If the requested offest is within
9022654012fSReza Sabdar  * the window but not within the current record, then the tape is
9032654012fSReza Sabdar  * positioned to the record containing the requested offest. The requested
9042654012fSReza Sabdar  * amount of data is then read from the tape device and written to the
9052654012fSReza Sabdar  * data connection.
9062654012fSReza Sabdar  *
9072654012fSReza Sabdar  * Parameters:
9082654012fSReza Sabdar  *   connection (input) - connection handle.
9092654012fSReza Sabdar  *   body       (input) - request message body.
9102654012fSReza Sabdar  *
9112654012fSReza Sabdar  * Returns:
9122654012fSReza Sabdar  *   void
9132654012fSReza Sabdar  */
9142654012fSReza Sabdar void
ndmpd_mover_read_v3(ndmp_connection_t * connection,void * body)9152654012fSReza Sabdar ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
9162654012fSReza Sabdar {
9172654012fSReza Sabdar 	ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
9182654012fSReza Sabdar 	ndmp_mover_read_reply reply;
9192654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
9202654012fSReza Sabdar 	int err;
9212654012fSReza Sabdar 
9222654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
9232654012fSReza Sabdar 
9242654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
9252654012fSReza Sabdar 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
9262654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
9272654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
9282654012fSReza Sabdar 	} else if (session->ns_mover.md_bytes_left_to_read != 0) {
9292654012fSReza Sabdar 		reply.error = NDMP_READ_IN_PROGRESS_ERR;
9302654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "In progress");
9312654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
9322654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
9332654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
9342654012fSReza Sabdar 	} else if (quad_to_long_long(request->length) == 0 ||
9352654012fSReza Sabdar 	    (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
9362654012fSReza Sabdar 	    quad_to_long_long(request->offset) != 0)) {
9372654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
9382654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Illegal args");
9392654012fSReza Sabdar 	} else {
9402654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
9412654012fSReza Sabdar 	}
9422654012fSReza Sabdar 
9432654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
9442654012fSReza Sabdar 	    "sending ndmp_mover_read_reply");
9452654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR)
9462654012fSReza Sabdar 		return;
9472654012fSReza Sabdar 
9482654012fSReza Sabdar 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
9492654012fSReza Sabdar 	    quad_to_long_long(request->length));
9502654012fSReza Sabdar 	if (err < 0) {
9512654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
9522654012fSReza Sabdar 		return;
9532654012fSReza Sabdar 	}
9542654012fSReza Sabdar 
9552654012fSReza Sabdar 	/*
9562654012fSReza Sabdar 	 * Just return if we are waiting for the DMA to complete the seek.
9572654012fSReza Sabdar 	 */
9582654012fSReza Sabdar 	if (err == 1)
9592654012fSReza Sabdar 		return;
9602654012fSReza Sabdar 
9612654012fSReza Sabdar 	/*
9622654012fSReza Sabdar 	 * Setup a handler function that will be called when
9632654012fSReza Sabdar 	 * data can be written to the data connection without blocking.
9642654012fSReza Sabdar 	 */
9652654012fSReza Sabdar 	if (ndmpd_add_file_handler(session, (void*)session,
9662654012fSReza Sabdar 	    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE, HC_MOVER,
9672654012fSReza Sabdar 	    mover_data_write_v3) < 0) {
9682654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
9692654012fSReza Sabdar 		return;
9702654012fSReza Sabdar 	}
9712654012fSReza Sabdar }
9722654012fSReza Sabdar 
9732654012fSReza Sabdar 
9742654012fSReza Sabdar /*
9752654012fSReza Sabdar  * ndmpd_mover_set_record_size_v3
9762654012fSReza Sabdar  *
9772654012fSReza Sabdar  * This handler handles mover_set_record_size requests.
9782654012fSReza Sabdar  *
9792654012fSReza Sabdar  * Parameters:
9802654012fSReza Sabdar  *   connection (input) - connection handle.
9812654012fSReza Sabdar  *   body       (input) - request message body.
9822654012fSReza Sabdar  *
9832654012fSReza Sabdar  * Returns:
9842654012fSReza Sabdar  *   void
9852654012fSReza Sabdar  */
9862654012fSReza Sabdar void
ndmpd_mover_set_record_size_v3(ndmp_connection_t * connection,void * body)9872654012fSReza Sabdar ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
9882654012fSReza Sabdar {
9892654012fSReza Sabdar 	ndmp_mover_set_record_size_request *request;
9902654012fSReza Sabdar 	ndmp_mover_set_record_size_reply reply;
9912654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
9922654012fSReza Sabdar 	char *cp;
9932654012fSReza Sabdar 
9942654012fSReza Sabdar 	request = (ndmp_mover_set_record_size_request *) body;
9952654012fSReza Sabdar 
9962654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
9972654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
9982654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mover state %d",
9992654012fSReza Sabdar 		    session->ns_mover.md_state);
10002654012fSReza Sabdar 	} else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
10012654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10022654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
10032654012fSReza Sabdar 		    "Invalid argument %d, should be > 0 and <= %d",
10042654012fSReza Sabdar 		    request->len, ndmp_max_mover_recsize);
10052654012fSReza Sabdar 	} else if (request->len == session->ns_mover.md_record_size)
10062654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
10072654012fSReza Sabdar 	else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
10082654012fSReza Sabdar 		reply.error = NDMP_NO_MEM_ERR;
10092654012fSReza Sabdar 	} else {
10102654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
10112654012fSReza Sabdar 		session->ns_mover.md_buf = cp;
10122654012fSReza Sabdar 		session->ns_mover.md_record_size = request->len;
10132654012fSReza Sabdar 		session->ns_mover.md_window_offset = 0;
10142654012fSReza Sabdar 		session->ns_mover.md_window_length = 0;
10152654012fSReza Sabdar 	}
10162654012fSReza Sabdar 
10172654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
10182654012fSReza Sabdar 	    "sending mover_set_record_size reply");
10192654012fSReza Sabdar }
10202654012fSReza Sabdar 
10212654012fSReza Sabdar 
10222654012fSReza Sabdar /*
10232654012fSReza Sabdar  * ndmpd_mover_connect_v3
10242654012fSReza Sabdar  *   Request handler. Connects the mover to either a local
10252654012fSReza Sabdar  *   or remote data server.
10262654012fSReza Sabdar  *
10272654012fSReza Sabdar  * Parameters:
10282654012fSReza Sabdar  *   connection (input) - connection handle.
10292654012fSReza Sabdar  *   body       (input) - request message body.
10302654012fSReza Sabdar  *
10312654012fSReza Sabdar  * Returns:
10322654012fSReza Sabdar  *   void
10332654012fSReza Sabdar  */
10342654012fSReza Sabdar void
ndmpd_mover_connect_v3(ndmp_connection_t * connection,void * body)10352654012fSReza Sabdar ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
10362654012fSReza Sabdar {
10372654012fSReza Sabdar 	ndmp_mover_connect_request_v3 *request;
10382654012fSReza Sabdar 	ndmp_mover_connect_reply_v3 reply;
10392654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
10402654012fSReza Sabdar 
10412654012fSReza Sabdar 	request = (ndmp_mover_connect_request_v3*)body;
10422654012fSReza Sabdar 
10432654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
10442654012fSReza Sabdar 
10452654012fSReza Sabdar 	if (request->mode != NDMP_MOVER_MODE_READ &&
10462654012fSReza Sabdar 	    request->mode != NDMP_MOVER_MODE_WRITE) {
10472654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10482654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
10492654012fSReza Sabdar 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
10502654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10512654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
10522654012fSReza Sabdar 		    request->addr.addr_type);
10532654012fSReza Sabdar 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
10542654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
10552654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
10562654012fSReza Sabdar 		    session->ns_mover.md_state);
10572654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
10582654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
10592654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No tape device open");
10602654012fSReza Sabdar 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
10612654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
10622654012fSReza Sabdar 		reply.error = NDMP_WRITE_PROTECT_ERR;
10632654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
10642654012fSReza Sabdar 	} else
10652654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
10662654012fSReza Sabdar 
10672654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
10682654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
10692654012fSReza Sabdar 		    "sending ndmp_mover_connect reply");
10702654012fSReza Sabdar 		return;
10712654012fSReza Sabdar 	}
10722654012fSReza Sabdar 
10732654012fSReza Sabdar 	switch (request->addr.addr_type) {
10742654012fSReza Sabdar 	case NDMP_ADDR_LOCAL:
10752654012fSReza Sabdar 		/*
10762654012fSReza Sabdar 		 * Verify that the data server is listening for a
10772654012fSReza Sabdar 		 * local connection.
10782654012fSReza Sabdar 		 */
10792654012fSReza Sabdar 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
10802654012fSReza Sabdar 		    session->ns_data.dd_listen_sock != -1) {
10812654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
10822654012fSReza Sabdar 			    "Data server is not in local listen state");
10832654012fSReza Sabdar 			reply.error = NDMP_ILLEGAL_STATE_ERR;
10842654012fSReza Sabdar 		} else
10852654012fSReza Sabdar 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
10862654012fSReza Sabdar 		break;
10872654012fSReza Sabdar 
10882654012fSReza Sabdar 	case NDMP_ADDR_TCP:
108997f7c475SJan Kryl 		reply.error = mover_connect_sock(session, request->mode,
10902654012fSReza Sabdar 		    request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
10912654012fSReza Sabdar 		break;
10922654012fSReza Sabdar 
10932654012fSReza Sabdar 	default:
10942654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10952654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
10962654012fSReza Sabdar 		    request->addr.addr_type);
10972654012fSReza Sabdar 	}
10982654012fSReza Sabdar 
10992654012fSReza Sabdar 	if (reply.error == NDMP_NO_ERR) {
11002654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type =
11012654012fSReza Sabdar 		    request->addr.addr_type;
11022654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
11032654012fSReza Sabdar 		session->ns_mover.md_mode = request->mode;
11042654012fSReza Sabdar 	}
11052654012fSReza Sabdar 
11062654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
11072654012fSReza Sabdar 	    "sending ndmp_mover_connect reply");
11082654012fSReza Sabdar }
11092654012fSReza Sabdar 
11102654012fSReza Sabdar 
11112654012fSReza Sabdar /*
11122654012fSReza Sabdar  * ************************************************************************
11132654012fSReza Sabdar  * NDMP V4 HANDLERS
11142654012fSReza Sabdar  * ************************************************************************
11152654012fSReza Sabdar  */
11162654012fSReza Sabdar 
11172654012fSReza Sabdar /*
11182654012fSReza Sabdar  * ndmpd_mover_get_state_v4
11192654012fSReza Sabdar  *
11202654012fSReza Sabdar  * This handler handles the ndmp_mover_get_state_request.
11212654012fSReza Sabdar  * Status information for the mover state machine is returned.
11222654012fSReza Sabdar  *
11232654012fSReza Sabdar  * Parameters:
11242654012fSReza Sabdar  *   connection (input) - connection handle.
11252654012fSReza Sabdar  *   body       (input) - request message body.
11262654012fSReza Sabdar  *
11272654012fSReza Sabdar  * Returns:
11282654012fSReza Sabdar  *   void
11292654012fSReza Sabdar  */
11302654012fSReza Sabdar /*ARGSUSED*/
11312654012fSReza Sabdar void
ndmpd_mover_get_state_v4(ndmp_connection_t * connection,void * body)11322654012fSReza Sabdar ndmpd_mover_get_state_v4(ndmp_connection_t *connection, void *body)
11332654012fSReza Sabdar {
11342654012fSReza Sabdar 	ndmp_mover_get_state_reply_v4 reply;
11352654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
11362654012fSReza Sabdar 
11372654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
11382654012fSReza Sabdar 
11392654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
11402654012fSReza Sabdar 	reply.state = session->ns_mover.md_state;
11412654012fSReza Sabdar 	reply.mode = session->ns_mover.md_mode;
11422654012fSReza Sabdar 	reply.pause_reason = session->ns_mover.md_pause_reason;
11432654012fSReza Sabdar 	reply.halt_reason = session->ns_mover.md_halt_reason;
11442654012fSReza Sabdar 	reply.record_size = session->ns_mover.md_record_size;
11452654012fSReza Sabdar 	reply.record_num = session->ns_mover.md_record_num;
11462654012fSReza Sabdar 	reply.bytes_moved =
11472654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_data_written);
11482654012fSReza Sabdar 	reply.seek_position =
11492654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_seek_position);
11502654012fSReza Sabdar 	reply.bytes_left_to_read =
11512654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
11522654012fSReza Sabdar 	reply.window_offset =
11532654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_offset);
11542654012fSReza Sabdar 	reply.window_length =
11552654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_length);
11562654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
11572654012fSReza Sabdar 		ndmp_copy_addr_v4(&reply.data_connection_addr,
11582654012fSReza Sabdar 		    &session->ns_mover.md_data_addr_v4);
11592654012fSReza Sabdar 
11602654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
11612654012fSReza Sabdar 	    "sending ndmp_mover_get_state reply");
11622654012fSReza Sabdar 	free(reply.data_connection_addr.tcp_addr_v4);
11632654012fSReza Sabdar }
11642654012fSReza Sabdar 
11652654012fSReza Sabdar 
11662654012fSReza Sabdar /*
11672654012fSReza Sabdar  * ndmpd_mover_listen_v4
11682654012fSReza Sabdar  *
11692654012fSReza Sabdar  * This handler handles ndmp_mover_listen_requests.
11702654012fSReza Sabdar  * A TCP/IP socket is created that is used to listen for
11712654012fSReza Sabdar  * and accept data connections initiated by a remote
11722654012fSReza Sabdar  * data server.
11732654012fSReza Sabdar  *
11742654012fSReza Sabdar  * Parameters:
11752654012fSReza Sabdar  *   connection (input) - connection handle.
11762654012fSReza Sabdar  *   body       (input) - request message body.
11772654012fSReza Sabdar  *
11782654012fSReza Sabdar  * Returns:
11792654012fSReza Sabdar  *   void
11802654012fSReza Sabdar  */
11812654012fSReza Sabdar void
ndmpd_mover_listen_v4(ndmp_connection_t * connection,void * body)11822654012fSReza Sabdar ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
11832654012fSReza Sabdar {
11842654012fSReza Sabdar 	ndmp_mover_listen_request_v4 *request;
11852654012fSReza Sabdar 
11862654012fSReza Sabdar 	ndmp_mover_listen_reply_v4 reply;
11872654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
11882654012fSReza Sabdar 	ulong_t addr;
11892654012fSReza Sabdar 	ushort_t port;
11902654012fSReza Sabdar 
11912654012fSReza Sabdar 	request = (ndmp_mover_listen_request_v4 *)body;
11922654012fSReza Sabdar 
11932654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
11942654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
11952654012fSReza Sabdar 
11962654012fSReza Sabdar 	if (request->mode != NDMP_MOVER_MODE_READ &&
11972654012fSReza Sabdar 	    request->mode != NDMP_MOVER_MODE_WRITE) {
11982654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
11992654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
12002654012fSReza Sabdar 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
12012654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
12022654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
12032654012fSReza Sabdar 		    request->addr_type);
12042654012fSReza Sabdar 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
12052654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
12062654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
12072654012fSReza Sabdar 		    "Invalid mover state to process listen request");
12082654012fSReza Sabdar 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
12092654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
12102654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
12112654012fSReza Sabdar 		    "Invalid data state to process listen request");
12122654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
12132654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
12142654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No tape device open");
12152654012fSReza Sabdar 	} else if (session->ns_mover.md_record_size == 0) {
12162654012fSReza Sabdar 		reply.error = NDMP_PRECONDITION_ERR;
12172654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
12182654012fSReza Sabdar 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
12192654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
12202654012fSReza Sabdar 		reply.error = NDMP_PERMISSION_ERR;
12212654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
12222654012fSReza Sabdar 	}
12232654012fSReza Sabdar 
12242654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
12252654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
12262654012fSReza Sabdar 		    "error sending ndmp_mover_listen reply");
12272654012fSReza Sabdar 		return;
12282654012fSReza Sabdar 	}
12292654012fSReza Sabdar 
12302654012fSReza Sabdar 	switch (request->addr_type) {
12312654012fSReza Sabdar 	case NDMP_ADDR_LOCAL:
12322654012fSReza Sabdar 		reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
12332654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
12342654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
12352654012fSReza Sabdar 		break;
12362654012fSReza Sabdar 	case NDMP_ADDR_TCP:
12372654012fSReza Sabdar 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
12382654012fSReza Sabdar 			reply.error = NDMP_IO_ERR;
12392654012fSReza Sabdar 			break;
12402654012fSReza Sabdar 		}
12412654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
12422654012fSReza Sabdar 
12432654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
12442654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
12452654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
12462654012fSReza Sabdar 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
12472654012fSReza Sabdar 
12482654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
12492654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
12502654012fSReza Sabdar 
12512654012fSReza Sabdar 		ndmp_copy_addr_v4(&reply.connect_addr,
12522654012fSReza Sabdar 		    &session->ns_mover.md_data_addr_v4);
12532654012fSReza Sabdar 
12542654012fSReza Sabdar 		/* For compatibility with V3 */
12552654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
12562654012fSReza Sabdar 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
12572654012fSReza Sabdar 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
12582654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
12592654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
12602654012fSReza Sabdar 		break;
12612654012fSReza Sabdar 	default:
12622654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
12632654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
12642654012fSReza Sabdar 		    request->addr_type);
12652654012fSReza Sabdar 	}
12662654012fSReza Sabdar 
12672654012fSReza Sabdar 	if (reply.error == NDMP_NO_ERR) {
12682654012fSReza Sabdar 		session->ns_mover.md_mode = request->mode;
12692654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
12702654012fSReza Sabdar 	}
12712654012fSReza Sabdar 
12722654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
12732654012fSReza Sabdar 	    "error sending ndmp_mover_listen reply");
12742654012fSReza Sabdar 	free(reply.connect_addr.tcp_addr_v4);
12752654012fSReza Sabdar }
12762654012fSReza Sabdar 
12772654012fSReza Sabdar /*
12782654012fSReza Sabdar  * ndmpd_mover_connect_v4
12792654012fSReza Sabdar  *   Request handler. Connects the mover to either a local
12802654012fSReza Sabdar  *   or remote data server.
12812654012fSReza Sabdar  *
12822654012fSReza Sabdar  * Parameters:
12832654012fSReza Sabdar  *   connection (input) - connection handle.
12842654012fSReza Sabdar  *   body       (input) - request message body.
12852654012fSReza Sabdar  *
12862654012fSReza Sabdar  * Returns:
12872654012fSReza Sabdar  *   void
12882654012fSReza Sabdar  */
12892654012fSReza Sabdar void
ndmpd_mover_connect_v4(ndmp_connection_t * connection,void * body)12902654012fSReza Sabdar ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
12912654012fSReza Sabdar {
12922654012fSReza Sabdar 	ndmp_mover_connect_request_v4 *request;
12932654012fSReza Sabdar 	ndmp_mover_connect_reply_v4 reply;
12942654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
12952654012fSReza Sabdar 
12962654012fSReza Sabdar 	request = (ndmp_mover_connect_request_v4 *)body;
12972654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
12982654012fSReza Sabdar 
12992654012fSReza Sabdar 	if (request->mode != NDMP_MOVER_MODE_READ &&
13002654012fSReza Sabdar 	    request->mode != NDMP_MOVER_MODE_WRITE) {
13012654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
13022654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
13032654012fSReza Sabdar 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
13042654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
13052654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
13062654012fSReza Sabdar 		    request->addr.addr_type);
13072654012fSReza Sabdar 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
13082654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
13092654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
13102654012fSReza Sabdar 		    session->ns_mover.md_state);
13112654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
13122654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
13132654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No tape device open");
13142654012fSReza Sabdar 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
13152654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
13162654012fSReza Sabdar 		reply.error = NDMP_PERMISSION_ERR;
13172654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
13182654012fSReza Sabdar 	} else if (session->ns_mover.md_record_size == 0) {
13192654012fSReza Sabdar 		reply.error = NDMP_PRECONDITION_ERR;
13202654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
13212654012fSReza Sabdar 	} else
13222654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
13232654012fSReza Sabdar 
13242654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
13252654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
13262654012fSReza Sabdar 		    "sending ndmp_mover_connect reply");
13272654012fSReza Sabdar 		return;
13282654012fSReza Sabdar 	}
13292654012fSReza Sabdar 
13302654012fSReza Sabdar 	switch (request->addr.addr_type) {
13312654012fSReza Sabdar 	case NDMP_ADDR_LOCAL:
13322654012fSReza Sabdar 		/*
13332654012fSReza Sabdar 		 * Verify that the data server is listening for a
13342654012fSReza Sabdar 		 * local connection.
13352654012fSReza Sabdar 		 */
13362654012fSReza Sabdar 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
13372654012fSReza Sabdar 		    session->ns_data.dd_listen_sock != -1) {
13382654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
13392654012fSReza Sabdar 			    "Data server is not in local listen state");
13402654012fSReza Sabdar 			reply.error = NDMP_ILLEGAL_STATE_ERR;
13412654012fSReza Sabdar 		} else
13422654012fSReza Sabdar 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
13432654012fSReza Sabdar 		break;
13442654012fSReza Sabdar 
13452654012fSReza Sabdar 	case NDMP_ADDR_TCP:
134697f7c475SJan Kryl 		reply.error = mover_connect_sock(session, request->mode,
13472654012fSReza Sabdar 		    request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
13482654012fSReza Sabdar 		break;
13492654012fSReza Sabdar 
13502654012fSReza Sabdar 	default:
13512654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
13522654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
13532654012fSReza Sabdar 		    request->addr.addr_type);
13542654012fSReza Sabdar 	}
13552654012fSReza Sabdar 
13562654012fSReza Sabdar 	if (reply.error == NDMP_NO_ERR) {
13572654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type =
13582654012fSReza Sabdar 		    request->addr.addr_type;
13592654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
13602654012fSReza Sabdar 		session->ns_mover.md_mode = request->mode;
13612654012fSReza Sabdar 	}
13622654012fSReza Sabdar 
13632654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
13642654012fSReza Sabdar 	    "sending ndmp_mover_connect reply");
13652654012fSReza Sabdar }
13662654012fSReza Sabdar 
13672654012fSReza Sabdar 
13682654012fSReza Sabdar 
13692654012fSReza Sabdar /*
13702654012fSReza Sabdar  * ************************************************************************
13712654012fSReza Sabdar  * LOCALS
13722654012fSReza Sabdar  * ************************************************************************
13732654012fSReza Sabdar  */
13742654012fSReza Sabdar 
13752654012fSReza Sabdar /*
13762654012fSReza Sabdar  * ndmpd_local_write
13772654012fSReza Sabdar  *
13782654012fSReza Sabdar  * Writes data to the mover.
13792654012fSReza Sabdar  * Buffers and write data to the tape device.
13802654012fSReza Sabdar  * A full tape record is buffered before being written.
13812654012fSReza Sabdar  *
13822654012fSReza Sabdar  * Parameters:
13832654012fSReza Sabdar  *   session    (input) - session pointer.
13842654012fSReza Sabdar  *   data       (input) - data to be written.
13852654012fSReza Sabdar  *   length     (input) - data length.
13862654012fSReza Sabdar  *
13872654012fSReza Sabdar  * Returns:
13882654012fSReza Sabdar  *   0 - data successfully written.
13892654012fSReza Sabdar  *  -1 - error.
13902654012fSReza Sabdar  */
13912654012fSReza Sabdar int
ndmpd_local_write(ndmpd_session_t * session,char * data,ulong_t length)13922654012fSReza Sabdar ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
13932654012fSReza Sabdar {
13942654012fSReza Sabdar 	ulong_t count = 0;
13952654012fSReza Sabdar 	ssize_t n;
13962654012fSReza Sabdar 	ulong_t len;
13972654012fSReza Sabdar 
13982654012fSReza Sabdar 	/*
13992654012fSReza Sabdar 	 * A length of 0 indicates that any buffered data should be
14002654012fSReza Sabdar 	 * flushed to tape.
14012654012fSReza Sabdar 	 */
14022654012fSReza Sabdar 	if (length == 0) {
14032654012fSReza Sabdar 		if (session->ns_mover.md_w_index == 0)
14042654012fSReza Sabdar 			return (0);
14052654012fSReza Sabdar 
14062654012fSReza Sabdar 		(void) memset(
14072654012fSReza Sabdar 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
14082654012fSReza Sabdar 		    0, session->ns_mover.md_record_size -
14092654012fSReza Sabdar 		    session->ns_mover.md_w_index);
14102654012fSReza Sabdar 
14119ee94b97SJan Kryl 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
14122654012fSReza Sabdar 		    session->ns_mover.md_record_size);
14132654012fSReza Sabdar 		if (n <= 0) {
14142654012fSReza Sabdar 			ndmpd_mover_error(session,
14152654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14162654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
14172654012fSReza Sabdar 			return (-1);
14182654012fSReza Sabdar 		}
14192654012fSReza Sabdar 		session->ns_mover.md_position += n;
14202654012fSReza Sabdar 		session->ns_mover.md_data_written +=
14212654012fSReza Sabdar 		    session->ns_mover.md_w_index;
14222654012fSReza Sabdar 		session->ns_mover.md_record_num++;
14232654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
14242654012fSReza Sabdar 		return (0);
14252654012fSReza Sabdar 	}
14262654012fSReza Sabdar 	/* Break the data into records. */
14272654012fSReza Sabdar 	while (count < length) {
14282654012fSReza Sabdar 		/*
14292654012fSReza Sabdar 		 * Determine if data needs to be buffered or
14302654012fSReza Sabdar 		 * can be written directly from user supplied location.
14312654012fSReza Sabdar 		 * We can fast path the write if there is no pending
14322654012fSReza Sabdar 		 * buffered data and there is at least a full record's worth
14332654012fSReza Sabdar 		 * of data to be written.
14342654012fSReza Sabdar 		 */
14352654012fSReza Sabdar 		if (session->ns_mover.md_w_index == 0 &&
14362654012fSReza Sabdar 		    length - count >= session->ns_mover.md_record_size) {
14379ee94b97SJan Kryl 			n = mover_tape_write_v3(session, &data[count],
14382654012fSReza Sabdar 			    session->ns_mover.md_record_size);
14392654012fSReza Sabdar 			if (n <= 0) {
14402654012fSReza Sabdar 				ndmpd_mover_error(session,
14412654012fSReza Sabdar 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14422654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
14432654012fSReza Sabdar 				return (-1);
14442654012fSReza Sabdar 			}
14452654012fSReza Sabdar 			session->ns_mover.md_position += n;
14462654012fSReza Sabdar 			session->ns_mover.md_data_written += n;
14472654012fSReza Sabdar 			session->ns_mover.md_record_num++;
14482654012fSReza Sabdar 			count += n;
14492654012fSReza Sabdar 			continue;
14502654012fSReza Sabdar 		}
14512654012fSReza Sabdar 		/* Buffer the data */
14522654012fSReza Sabdar 		len = length - count;
14532654012fSReza Sabdar 		if (len > session->ns_mover.md_record_size -
14542654012fSReza Sabdar 		    session->ns_mover.md_w_index)
14552654012fSReza Sabdar 			len = session->ns_mover.md_record_size -
14562654012fSReza Sabdar 			    session->ns_mover.md_w_index;
14572654012fSReza Sabdar 
14582654012fSReza Sabdar 		(void) memcpy(
14592654012fSReza Sabdar 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
14602654012fSReza Sabdar 		    &data[count], len);
14612654012fSReza Sabdar 		session->ns_mover.md_w_index += len;
14622654012fSReza Sabdar 		count += len;
14632654012fSReza Sabdar 
14642654012fSReza Sabdar 		/* Write the buffer if its full */
14652654012fSReza Sabdar 		if (session->ns_mover.md_w_index ==
14662654012fSReza Sabdar 		    session->ns_mover.md_record_size) {
14679ee94b97SJan Kryl 			n = mover_tape_write_v3(session,
14689ee94b97SJan Kryl 			    session->ns_mover.md_buf,
14692654012fSReza Sabdar 			    session->ns_mover.md_record_size);
14709ee94b97SJan Kryl 			if (n <= 0) {
14712654012fSReza Sabdar 				ndmpd_mover_error(session,
14722654012fSReza Sabdar 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14732654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
14742654012fSReza Sabdar 				return (-1);
14752654012fSReza Sabdar 			}
14762654012fSReza Sabdar 			session->ns_mover.md_position += n;
14772654012fSReza Sabdar 			session->ns_mover.md_data_written += n;
14782654012fSReza Sabdar 			session->ns_mover.md_record_num++;
14792654012fSReza Sabdar 			session->ns_mover.md_w_index = 0;
14802654012fSReza Sabdar 		}
14812654012fSReza Sabdar 	}
14822654012fSReza Sabdar 
14832654012fSReza Sabdar 	return (0);
14842654012fSReza Sabdar }
14852654012fSReza Sabdar 
14862654012fSReza Sabdar 
14872654012fSReza Sabdar /*
14882654012fSReza Sabdar  * ndmpd_remote_write
14892654012fSReza Sabdar  *
14902654012fSReza Sabdar  * Writes data to the remote mover.
14912654012fSReza Sabdar  *
14922654012fSReza Sabdar  * Parameters:
14932654012fSReza Sabdar  *   session    (input) - session pointer.
14942654012fSReza Sabdar  *   data       (input) - data to be written.
14952654012fSReza Sabdar  *   length     (input) - data length.
14962654012fSReza Sabdar  *
14972654012fSReza Sabdar  * Returns:
14982654012fSReza Sabdar  *   0 - data successfully written.
14992654012fSReza Sabdar  *  -1 - error.
15002654012fSReza Sabdar  */
15012654012fSReza Sabdar int
ndmpd_remote_write(ndmpd_session_t * session,char * data,ulong_t length)15022654012fSReza Sabdar ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
15032654012fSReza Sabdar {
15042654012fSReza Sabdar 	ssize_t n;
15052654012fSReza Sabdar 	ulong_t count = 0;
15062654012fSReza Sabdar 
15072654012fSReza Sabdar 	while (count < length) {
15082654012fSReza Sabdar 		if (session->ns_eof == TRUE ||
15092654012fSReza Sabdar 		    session->ns_data.dd_abort == TRUE)
15102654012fSReza Sabdar 			return (-1);
15112654012fSReza Sabdar 
15122654012fSReza Sabdar 		if ((n = write(session->ns_data.dd_sock, &data[count],
15132654012fSReza Sabdar 		    length - count)) < 0) {
15142654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Socket write error: %m.");
15152654012fSReza Sabdar 			return (-1);
15162654012fSReza Sabdar 		}
15172654012fSReza Sabdar 		count += n;
15182654012fSReza Sabdar 	}
15192654012fSReza Sabdar 
15202654012fSReza Sabdar 	return (0);
15212654012fSReza Sabdar }
15222654012fSReza Sabdar 
15232654012fSReza Sabdar /*
15242654012fSReza Sabdar  * ndmpd_local_read
15252654012fSReza Sabdar  *
15262654012fSReza Sabdar  * Reads data from the local tape device.
15272654012fSReza Sabdar  * Full tape records are read and buffered.
15282654012fSReza Sabdar  *
15292654012fSReza Sabdar  * Parameters:
15302654012fSReza Sabdar  *   session (input) - session pointer.
15312654012fSReza Sabdar  *   data    (input) - location to store data.
15322654012fSReza Sabdar  *   length  (input) - data length.
15332654012fSReza Sabdar  *
15342654012fSReza Sabdar  * Returns:
15352654012fSReza Sabdar  *   0 - data successfully read.
15362654012fSReza Sabdar  *  -1 - error.
15372654012fSReza Sabdar  *   1 - session terminated or operation aborted.
15382654012fSReza Sabdar  */
15392654012fSReza Sabdar int
ndmpd_local_read(ndmpd_session_t * session,char * data,ulong_t length)15402654012fSReza Sabdar ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
15412654012fSReza Sabdar {
15422654012fSReza Sabdar 	ulong_t count = 0;
15432654012fSReza Sabdar 	ssize_t n;
15442654012fSReza Sabdar 	ulong_t len;
15452654012fSReza Sabdar 	ndmp_notify_mover_paused_request pause_request;
15462654012fSReza Sabdar 
15472654012fSReza Sabdar 	/*
15482654012fSReza Sabdar 	 * Automatically increase the seek window if necessary.
15492654012fSReza Sabdar 	 * This is needed in the event the module attempts to read
15502654012fSReza Sabdar 	 * past a seek window set via a prior call to ndmpd_seek() or
15512654012fSReza Sabdar 	 * the module has not issued a seek. If no seek was issued then
15522654012fSReza Sabdar 	 * pretend that a seek was issued to read the entire tape.
15532654012fSReza Sabdar 	 */
15542654012fSReza Sabdar 	if (length > session->ns_mover.md_bytes_left_to_read) {
15552654012fSReza Sabdar 		/* ndmpd_seek() never called? */
15562654012fSReza Sabdar 		if (session->ns_data.dd_read_length == 0) {
15572654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read = ~0LL;
15582654012fSReza Sabdar 			session->ns_data.dd_read_offset = 0LL;
15592654012fSReza Sabdar 			session->ns_data.dd_read_length = ~0LL;
15602654012fSReza Sabdar 		} else {
15612654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read = length;
15622654012fSReza Sabdar 			session->ns_data.dd_read_offset =
15632654012fSReza Sabdar 			    session->ns_mover.md_position;
15642654012fSReza Sabdar 			session->ns_data.dd_read_length = length;
15652654012fSReza Sabdar 		}
15662654012fSReza Sabdar 	}
15672654012fSReza Sabdar 	/*
15682654012fSReza Sabdar 	 * Read as many records as necessary to satisfy the request.
15692654012fSReza Sabdar 	 */
15702654012fSReza Sabdar 	while (count < length) {
15712654012fSReza Sabdar 		/*
15722654012fSReza Sabdar 		 * If the end of the mover window has been reached,
15732654012fSReza Sabdar 		 * then notify the client that a new data window is needed.
15742654012fSReza Sabdar 		 */
15752654012fSReza Sabdar 		if (session->ns_mover.md_position >=
15762654012fSReza Sabdar 		    session->ns_mover.md_window_offset +
15772654012fSReza Sabdar 		    session->ns_mover.md_window_length) {
15782654012fSReza Sabdar 
15792654012fSReza Sabdar 			session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
15802654012fSReza Sabdar 			session->ns_mover.md_pause_reason =
15812654012fSReza Sabdar 			    NDMP_MOVER_PAUSE_SEEK;
15822654012fSReza Sabdar 			pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
15832654012fSReza Sabdar 			pause_request.seek_position =
15842654012fSReza Sabdar 			    long_long_to_quad(session->ns_mover.md_position);
15852654012fSReza Sabdar 
15862654012fSReza Sabdar 			if (ndmp_send_request(session->ns_connection,
15872654012fSReza Sabdar 			    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
15882654012fSReza Sabdar 			    (void *) &pause_request, 0) < 0) {
15892654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
15902654012fSReza Sabdar 				    "Sending notify_mover_paused request");
15912654012fSReza Sabdar 				ndmpd_mover_error(session,
15922654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
15932654012fSReza Sabdar 				return (-1);
15942654012fSReza Sabdar 			}
15952654012fSReza Sabdar 			/*
15968c4f9701SJanice Chang 			 * Wait until the state is changed by
15972654012fSReza Sabdar 			 * an abort or continue request.
15982654012fSReza Sabdar 			 */
1599a23888a3SJan Kryl 			if (ndmp_wait_for_mover(session) != 0)
1600a23888a3SJan Kryl 				return (1);
16012654012fSReza Sabdar 		}
16022654012fSReza Sabdar 		len = length - count;
16032654012fSReza Sabdar 
16042654012fSReza Sabdar 		/*
16052654012fSReza Sabdar 		 * Prevent reading past the end of the window.
16062654012fSReza Sabdar 		 */
16072654012fSReza Sabdar 		if (len >
16082654012fSReza Sabdar 		    session->ns_mover.md_window_offset +
16092654012fSReza Sabdar 		    session->ns_mover.md_window_length -
16102654012fSReza Sabdar 		    session->ns_mover.md_position)
16112654012fSReza Sabdar 			len = session->ns_mover.md_window_offset +
16122654012fSReza Sabdar 			    session->ns_mover.md_window_length -
16132654012fSReza Sabdar 			    session->ns_mover.md_position;
16142654012fSReza Sabdar 
16152654012fSReza Sabdar 		/*
16162654012fSReza Sabdar 		 * Copy from the data buffer first.
16172654012fSReza Sabdar 		 */
16182654012fSReza Sabdar 		if (session->ns_mover.md_w_index -
16192654012fSReza Sabdar 		    session->ns_mover.md_r_index != 0) {
16202654012fSReza Sabdar 			/*
16212654012fSReza Sabdar 			 * Limit the copy to the amount of data in the buffer.
16222654012fSReza Sabdar 			 */
16232654012fSReza Sabdar 			if (len > session->ns_mover.md_w_index -
16242654012fSReza Sabdar 			    session->ns_mover.md_r_index)
16252654012fSReza Sabdar 				len = session->ns_mover.md_w_index
16262654012fSReza Sabdar 				    - session->ns_mover.md_r_index;
16272654012fSReza Sabdar 
16282654012fSReza Sabdar 			(void) memcpy((void *) &data[count],
16292654012fSReza Sabdar 			    &session->ns_mover.md_buf[session->
16302654012fSReza Sabdar 			    ns_mover.md_r_index], len);
16312654012fSReza Sabdar 			count += len;
16322654012fSReza Sabdar 			session->ns_mover.md_r_index += len;
16332654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read -= len;
16342654012fSReza Sabdar 			session->ns_mover.md_position += len;
16352654012fSReza Sabdar 			continue;
16362654012fSReza Sabdar 		}
16372654012fSReza Sabdar 		/*
16382654012fSReza Sabdar 		 * Determine if data needs to be buffered or
16392654012fSReza Sabdar 		 * can be read directly to user supplied location.
16402654012fSReza Sabdar 		 * We can fast path the read if at least a full record
16412654012fSReza Sabdar 		 * needs to be read and there is no seek pending.
16422654012fSReza Sabdar 		 * This is done to eliminate a buffer copy.
16432654012fSReza Sabdar 		 */
16442654012fSReza Sabdar 		if (len >= session->ns_mover.md_record_size &&
16452654012fSReza Sabdar 		    session->ns_mover.md_position >=
16462654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
16472654012fSReza Sabdar 			n = tape_read(session, &data[count]);
16482654012fSReza Sabdar 			if (n <= 0) {
16492654012fSReza Sabdar 				if (n == TAPE_NO_WRITER_ERR)
16502654012fSReza Sabdar 					return (1);
16512654012fSReza Sabdar 
16522654012fSReza Sabdar 				ndmpd_mover_error(session,
16532654012fSReza Sabdar 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
16542654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
16552654012fSReza Sabdar 				return (n == 0) ? (1) : (-1);
16562654012fSReza Sabdar 			}
16572654012fSReza Sabdar 			count += n;
16582654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read -= n;
16592654012fSReza Sabdar 			session->ns_mover.md_position += n;
16602654012fSReza Sabdar 			continue;
16612654012fSReza Sabdar 		}
16622654012fSReza Sabdar 		/* Read the next record into the buffer. */
16632654012fSReza Sabdar 		n = tape_read(session, session->ns_mover.md_buf);
16642654012fSReza Sabdar 		if (n <= 0) {
16652654012fSReza Sabdar 			if (n == TAPE_NO_WRITER_ERR)
16662654012fSReza Sabdar 				return (1);
16672654012fSReza Sabdar 
16682654012fSReza Sabdar 			ndmpd_mover_error(session,
16692654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
16702654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
16712654012fSReza Sabdar 			return (n == 0) ? (1) : (-1);
16722654012fSReza Sabdar 		}
16732654012fSReza Sabdar 		session->ns_mover.md_w_index = n;
16742654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
16752654012fSReza Sabdar 
16762654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
16772654012fSReza Sabdar 
16782654012fSReza Sabdar 		/*
16792654012fSReza Sabdar 		 * Discard data if the current data stream position is
16802654012fSReza Sabdar 		 * prior to the seek position. This is necessary if a seek
16812654012fSReza Sabdar 		 * request set the seek pointer to a position that is not a
16822654012fSReza Sabdar 		 * record boundary. The seek request handler can only position
16832654012fSReza Sabdar 		 * to the start of a record.
16842654012fSReza Sabdar 		 */
16852654012fSReza Sabdar 		if (session->ns_mover.md_position <
16862654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
16872654012fSReza Sabdar 			session->ns_mover.md_r_index =
16882654012fSReza Sabdar 			    session->ns_mover.md_seek_position -
16892654012fSReza Sabdar 			    session->ns_mover.md_position;
16902654012fSReza Sabdar 			session->ns_mover.md_position =
16912654012fSReza Sabdar 			    session->ns_mover.md_seek_position;
16922654012fSReza Sabdar 		}
16932654012fSReza Sabdar 	}
16942654012fSReza Sabdar 
16952654012fSReza Sabdar 	return (0);
16962654012fSReza Sabdar }
16972654012fSReza Sabdar 
16982654012fSReza Sabdar 
16992654012fSReza Sabdar /*
17002654012fSReza Sabdar  * ndmpd_remote_read
17012654012fSReza Sabdar  *
17022654012fSReza Sabdar  * Reads data from the remote mover.
17032654012fSReza Sabdar  *
17042654012fSReza Sabdar  * Parameters:
17052654012fSReza Sabdar  *   session (input) - session pointer.
17062654012fSReza Sabdar  *   data    (input) - data to be written.
17072654012fSReza Sabdar  *   length  (input) - data length.
17082654012fSReza Sabdar  *
17092654012fSReza Sabdar  * Returns:
17102654012fSReza Sabdar  *   0 - data successfully read.
17112654012fSReza Sabdar  *  -1 - error.
17122654012fSReza Sabdar  *   1 - session terminated or operation aborted.
17132654012fSReza Sabdar  */
17142654012fSReza Sabdar int
ndmpd_remote_read(ndmpd_session_t * session,char * data,ulong_t length)17152654012fSReza Sabdar ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
17162654012fSReza Sabdar {
17172654012fSReza Sabdar 	ulong_t count = 0;
17182654012fSReza Sabdar 	ssize_t n;
17192654012fSReza Sabdar 	ulong_t len;
17202654012fSReza Sabdar 	ndmp_notify_data_read_request request;
17212654012fSReza Sabdar 
17222654012fSReza Sabdar 	while (count < length) {
17232654012fSReza Sabdar 		len = length - count;
17242654012fSReza Sabdar 
17252654012fSReza Sabdar 		/*
17262654012fSReza Sabdar 		 * If the end of the seek window has been reached then
17272654012fSReza Sabdar 		 * send an ndmp_read request to the client.
17282654012fSReza Sabdar 		 * The NDMP client will then send a mover_data_read request to
17292654012fSReza Sabdar 		 * the remote mover and the mover will send more data.
17302654012fSReza Sabdar 		 * This condition can occur if the module attempts to read past
17312654012fSReza Sabdar 		 * a seek window set via a prior call to ndmpd_seek() or
17322654012fSReza Sabdar 		 * the module has not issued a seek. If no seek was issued then
17332654012fSReza Sabdar 		 * pretend that a seek was issued to read the entire tape.
17342654012fSReza Sabdar 		 */
17352654012fSReza Sabdar 		if (session->ns_mover.md_bytes_left_to_read == 0) {
17362654012fSReza Sabdar 			/* ndmpd_seek() never called? */
17372654012fSReza Sabdar 			if (session->ns_data.dd_read_length == 0) {
17382654012fSReza Sabdar 				session->ns_mover.md_bytes_left_to_read = ~0LL;
17392654012fSReza Sabdar 				session->ns_data.dd_read_offset = 0LL;
17402654012fSReza Sabdar 				session->ns_data.dd_read_length = ~0LL;
17412654012fSReza Sabdar 			} else {
17422654012fSReza Sabdar 				session->ns_mover.md_bytes_left_to_read = len;
17432654012fSReza Sabdar 				session->ns_data.dd_read_offset =
17442654012fSReza Sabdar 				    session->ns_mover.md_position;
17452654012fSReza Sabdar 				session->ns_data.dd_read_length = len;
17462654012fSReza Sabdar 			}
17472654012fSReza Sabdar 
17482654012fSReza Sabdar 			request.offset =
17492654012fSReza Sabdar 			    long_long_to_quad(session->ns_data.dd_read_offset);
17502654012fSReza Sabdar 			request.length =
17512654012fSReza Sabdar 			    long_long_to_quad(session->ns_data.dd_read_length);
17522654012fSReza Sabdar 
17537bc22e45SReza Sabdar 			if (ndmp_send_request_lock(session->ns_connection,
17542654012fSReza Sabdar 			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
17552654012fSReza Sabdar 			    (void *) &request, 0) < 0) {
17562654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
17572654012fSReza Sabdar 				    "Sending notify_data_read request");
17582654012fSReza Sabdar 				return (-1);
17592654012fSReza Sabdar 			}
17602654012fSReza Sabdar 		}
17612654012fSReza Sabdar 		if (session->ns_eof == TRUE ||
17622654012fSReza Sabdar 		    session->ns_data.dd_abort == TRUE)
17632654012fSReza Sabdar 			return (1);
17642654012fSReza Sabdar 
17652654012fSReza Sabdar 		/*
17662654012fSReza Sabdar 		 * If the module called ndmpd_seek() prior to reading all of the
17672654012fSReza Sabdar 		 * data that the remote mover was requested to send, then the
17682654012fSReza Sabdar 		 * excess data from the seek has to be discardd.
17692654012fSReza Sabdar 		 */
17702654012fSReza Sabdar 		if (session->ns_mover.md_discard_length != 0) {
17712654012fSReza Sabdar 			n = discard_data(session,
17722654012fSReza Sabdar 			    (ulong_t)session->ns_mover.md_discard_length);
17732654012fSReza Sabdar 			if (n < 0)
17742654012fSReza Sabdar 				return (-1);
17752654012fSReza Sabdar 			session->ns_mover.md_discard_length -= n;
17762654012fSReza Sabdar 			continue;
17772654012fSReza Sabdar 		}
17782654012fSReza Sabdar 		/*
17792654012fSReza Sabdar 		 * Don't attempt to read more data than the remote is sending.
17802654012fSReza Sabdar 		 */
17812654012fSReza Sabdar 		if (len > session->ns_mover.md_bytes_left_to_read)
17822654012fSReza Sabdar 			len = session->ns_mover.md_bytes_left_to_read;
17832654012fSReza Sabdar 
17842654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "len: %u", len);
17852654012fSReza Sabdar 
17862654012fSReza Sabdar 		if ((n = read(session->ns_data.dd_sock, &data[count],
17872654012fSReza Sabdar 		    len)) < 0) {
17882654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
17892654012fSReza Sabdar 			return (-1);
17902654012fSReza Sabdar 		}
17912654012fSReza Sabdar 		/* read returns 0 if the connection was closed */
17922654012fSReza Sabdar 		if (n == 0)
17932654012fSReza Sabdar 			return (-1);
17942654012fSReza Sabdar 
17952654012fSReza Sabdar 		count += n;
17962654012fSReza Sabdar 		session->ns_mover.md_bytes_left_to_read -= n;
17972654012fSReza Sabdar 		session->ns_mover.md_position += n;
17982654012fSReza Sabdar 	}
17992654012fSReza Sabdar 
18002654012fSReza Sabdar 	return (0);
18012654012fSReza Sabdar }
18022654012fSReza Sabdar 
18032654012fSReza Sabdar /* *** ndmpd internal functions ***************************************** */
18042654012fSReza Sabdar 
18052654012fSReza Sabdar /*
18062654012fSReza Sabdar  * ndmpd_mover_init
18072654012fSReza Sabdar  *
18082654012fSReza Sabdar  * Initialize mover specific session variables.
18092654012fSReza Sabdar  * Don't initialize variables such as record_size that need to
18102654012fSReza Sabdar  * persist across data operations. A client may open a connection and
18112654012fSReza Sabdar  * do multiple backups after setting the record_size.
18122654012fSReza Sabdar  *
18132654012fSReza Sabdar  * Parameters:
18142654012fSReza Sabdar  *   session (input) - session pointer.
18152654012fSReza Sabdar  *
18162654012fSReza Sabdar  * Returns:
18172654012fSReza Sabdar  *   0 - success.
18182654012fSReza Sabdar  *  -1 - error.
18192654012fSReza Sabdar  */
18202654012fSReza Sabdar int
ndmpd_mover_init(ndmpd_session_t * session)18212654012fSReza Sabdar ndmpd_mover_init(ndmpd_session_t *session)
18222654012fSReza Sabdar {
18232654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
18242654012fSReza Sabdar 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
18252654012fSReza Sabdar 	session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
18262654012fSReza Sabdar 	session->ns_mover.md_data_written = 0LL;
18272654012fSReza Sabdar 	session->ns_mover.md_seek_position = 0LL;
18282654012fSReza Sabdar 	session->ns_mover.md_bytes_left_to_read = 0LL;
18292654012fSReza Sabdar 	session->ns_mover.md_window_offset = 0LL;
18302654012fSReza Sabdar 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
18312654012fSReza Sabdar 	session->ns_mover.md_position = 0LL;
18322654012fSReza Sabdar 	session->ns_mover.md_discard_length = 0;
18332654012fSReza Sabdar 	session->ns_mover.md_record_num = 0;
18342654012fSReza Sabdar 	session->ns_mover.md_record_size = 0;
18352654012fSReza Sabdar 	session->ns_mover.md_listen_sock = -1;
18362654012fSReza Sabdar 	session->ns_mover.md_pre_cond = FALSE;
18372654012fSReza Sabdar 	session->ns_mover.md_sock = -1;
18382654012fSReza Sabdar 	session->ns_mover.md_r_index = 0;
18392654012fSReza Sabdar 	session->ns_mover.md_w_index = 0;
18402654012fSReza Sabdar 	session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
18412654012fSReza Sabdar 	if (!session->ns_mover.md_buf)
18422654012fSReza Sabdar 		return (-1);
18432654012fSReza Sabdar 
18442654012fSReza Sabdar 	if (ndmp_get_version(session->ns_connection) == NDMPV3) {
18452654012fSReza Sabdar 		session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
18462654012fSReza Sabdar 		(void) memset(&session->ns_mover.md_data_addr, 0,
18472654012fSReza Sabdar 		    sizeof (ndmp_addr_v3));
18482654012fSReza Sabdar 	}
18492654012fSReza Sabdar 	return (0);
18502654012fSReza Sabdar }
18512654012fSReza Sabdar 
18522654012fSReza Sabdar 
18532654012fSReza Sabdar /*
18542654012fSReza Sabdar  * ndmpd_mover_shut_down
18552654012fSReza Sabdar  *
18562654012fSReza Sabdar  * Shutdown the mover. It closes all the sockets.
18572654012fSReza Sabdar  *
18582654012fSReza Sabdar  * Parameters:
18592654012fSReza Sabdar  *   session (input) - session pointer.
18602654012fSReza Sabdar  *
18612654012fSReza Sabdar  * Returns:
18622654012fSReza Sabdar  *   void
18632654012fSReza Sabdar  */
18642654012fSReza Sabdar void
ndmpd_mover_shut_down(ndmpd_session_t * session)18652654012fSReza Sabdar ndmpd_mover_shut_down(ndmpd_session_t *session)
18662654012fSReza Sabdar {
1867a23888a3SJan Kryl 	ndmp_lbr_params_t *nlp;
1868a23888a3SJan Kryl 
1869a23888a3SJan Kryl 	if ((nlp = ndmp_get_nlp(session)) == NULL)
1870a23888a3SJan Kryl 		return;
1871a23888a3SJan Kryl 
1872a23888a3SJan Kryl 	(void) mutex_lock(&nlp->nlp_mtx);
18732654012fSReza Sabdar 	if (session->ns_mover.md_listen_sock != -1) {
18742654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
18752654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
18762654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
18772654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
18782654012fSReza Sabdar 		(void) close(session->ns_mover.md_listen_sock);
18792654012fSReza Sabdar 		session->ns_mover.md_listen_sock = -1;
18802654012fSReza Sabdar 	}
18812654012fSReza Sabdar 	if (session->ns_mover.md_sock != -1) {
18822654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
18832654012fSReza Sabdar 		    session->ns_mover.md_sock);
18842654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
18852654012fSReza Sabdar 		    session->ns_mover.md_sock);
18862654012fSReza Sabdar 		(void) close(session->ns_mover.md_sock);
18872654012fSReza Sabdar 		session->ns_mover.md_sock = -1;
18882654012fSReza Sabdar 	}
1889a23888a3SJan Kryl 	(void) cond_broadcast(&nlp->nlp_cv);
1890a23888a3SJan Kryl 	(void) mutex_unlock(&nlp->nlp_mtx);
18912654012fSReza Sabdar }
18922654012fSReza Sabdar 
18932654012fSReza Sabdar 
18942654012fSReza Sabdar /*
18952654012fSReza Sabdar  * ndmpd_mover_cleanup
18962654012fSReza Sabdar  *
18972654012fSReza Sabdar  * Parameters:
18982654012fSReza Sabdar  *   session (input) - session pointer.
18992654012fSReza Sabdar  *
19002654012fSReza Sabdar  * Returns:
19012654012fSReza Sabdar  *   void
19022654012fSReza Sabdar  */
19032654012fSReza Sabdar void
ndmpd_mover_cleanup(ndmpd_session_t * session)19042654012fSReza Sabdar ndmpd_mover_cleanup(ndmpd_session_t *session)
19052654012fSReza Sabdar {
19062654012fSReza Sabdar 	NDMP_FREE(session->ns_mover.md_buf);
19072654012fSReza Sabdar }
19082654012fSReza Sabdar 
19092654012fSReza Sabdar 
19102654012fSReza Sabdar /*
19112654012fSReza Sabdar  * ndmpd_mover_connect
19122654012fSReza Sabdar  *   Create a connection to the specified mover.
19132654012fSReza Sabdar  *
19142654012fSReza Sabdar  * Parameters:
19152654012fSReza Sabdar  *   session (input) - session pointer
19162654012fSReza Sabdar  *
19172654012fSReza Sabdar  * Returns:
19182654012fSReza Sabdar  *   error code.
19192654012fSReza Sabdar  */
19202654012fSReza Sabdar ndmp_error
ndmpd_mover_connect(ndmpd_session_t * session,ndmp_mover_mode mover_mode)19212654012fSReza Sabdar ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
19222654012fSReza Sabdar {
19232654012fSReza Sabdar 	ndmp_mover_addr *mover = &session->ns_data.dd_mover;
19242654012fSReza Sabdar 	struct sockaddr_in sin;
19252654012fSReza Sabdar 	int sock = -1;
19262654012fSReza Sabdar 
19272654012fSReza Sabdar 	if (mover->addr_type == NDMP_ADDR_TCP) {
19282654012fSReza Sabdar 		if (mover->ndmp_mover_addr_u.addr.ip_addr) {
19292654012fSReza Sabdar 			(void) memset((void *) &sin, 0, sizeof (sin));
19302654012fSReza Sabdar 			sin.sin_family = AF_INET;
19312654012fSReza Sabdar 			sin.sin_addr.s_addr =
19322654012fSReza Sabdar 			    htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
19332654012fSReza Sabdar 			sin.sin_port =
19342654012fSReza Sabdar 			    htons(mover->ndmp_mover_addr_u.addr.port);
19352654012fSReza Sabdar 
19362654012fSReza Sabdar 			/*
19372654012fSReza Sabdar 			 * If the address type is TCP but both the address and
19382654012fSReza Sabdar 			 * the port number are zero, we have to use a different
19392654012fSReza Sabdar 			 * socket than the mover socket. This can happen when
19402654012fSReza Sabdar 			 * using NDMP disk to disk copy (AKA D2D copy).
19412654012fSReza Sabdar 			 * The NDMPCopy client will send a zero address to
19422654012fSReza Sabdar 			 * direct the server to use the mover socket as the
19432654012fSReza Sabdar 			 * data socket to receive the recovery data.
19442654012fSReza Sabdar 			 */
19452654012fSReza Sabdar 			if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
19462654012fSReza Sabdar 				session->ns_data.dd_sock =
19472654012fSReza Sabdar 				    session->ns_mover.md_sock;
19482654012fSReza Sabdar 				return (NDMP_NO_ERR);
19492654012fSReza Sabdar 			}
19502654012fSReza Sabdar 
19512654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
19522654012fSReza Sabdar 			    mover->ndmp_mover_addr_u.addr.ip_addr,
19532654012fSReza Sabdar 			    (ulong_t)sin.sin_port);
19542654012fSReza Sabdar 
19552654012fSReza Sabdar 			if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
19562654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Socket error: %m");
19572654012fSReza Sabdar 				return (NDMP_IO_ERR);
19582654012fSReza Sabdar 			}
19592654012fSReza Sabdar 			if (connect(sock, (struct sockaddr *)&sin,
19602654012fSReza Sabdar 			    sizeof (sin)) < 0) {
19612654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Connect error: %m");
19622654012fSReza Sabdar 				(void) close(sock);
19632654012fSReza Sabdar 				return (NDMP_IO_ERR);
19642654012fSReza Sabdar 			}
196597f7c475SJan Kryl 			set_socket_options(sock);
19662654012fSReza Sabdar 		} else {
19672654012fSReza Sabdar 			if ((session->ns_mover.md_state !=
19682654012fSReza Sabdar 			    NDMP_MOVER_STATE_ACTIVE) ||
19692654012fSReza Sabdar 			    (session->ns_mover.md_sock == -1)) {
19702654012fSReza Sabdar 
19712654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
19722654012fSReza Sabdar 				    "Not in active  state mover"
19732654012fSReza Sabdar 				    "  state = %d or Invalid mover sock=%d",
19742654012fSReza Sabdar 				    session->ns_mover.md_state,
19752654012fSReza Sabdar 				    session->ns_mover.md_sock);
19762654012fSReza Sabdar 				return (NDMP_ILLEGAL_STATE_ERR);
19772654012fSReza Sabdar 			}
19782654012fSReza Sabdar 
19792654012fSReza Sabdar 			sock = session->ns_mover.md_sock;
19802654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
19812654012fSReza Sabdar 			    "session: 0x%x setting data sock fd: %d to be"
19822654012fSReza Sabdar 			    " same as listen_sock", session, sock);
19832654012fSReza Sabdar 		}
19842654012fSReza Sabdar 
19852654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
19862654012fSReza Sabdar 
19872654012fSReza Sabdar 		session->ns_data.dd_sock = sock;
19882654012fSReza Sabdar 
19892654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
19902654012fSReza Sabdar 
19912654012fSReza Sabdar 		return (NDMP_NO_ERR);
19922654012fSReza Sabdar 	}
19932654012fSReza Sabdar 	/* Local mover connection. */
19942654012fSReza Sabdar 
19952654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
19962654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
19972654012fSReza Sabdar 		return (NDMP_ILLEGAL_STATE_ERR);
19982654012fSReza Sabdar 	}
19992654012fSReza Sabdar 	if (session->ns_tape.td_fd == -1) {
20002654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Tape device not open");
20012654012fSReza Sabdar 		return (NDMP_DEV_NOT_OPEN_ERR);
20022654012fSReza Sabdar 	}
20032654012fSReza Sabdar 	if (mover_mode == NDMP_MOVER_MODE_READ &&
20042654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
20052654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
20062654012fSReza Sabdar 		return (NDMP_WRITE_PROTECT_ERR);
20072654012fSReza Sabdar 	}
20082654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
20092654012fSReza Sabdar 	session->ns_mover.md_mode = mover_mode;
20102654012fSReza Sabdar 
20112654012fSReza Sabdar 	return (NDMP_NO_ERR);
20122654012fSReza Sabdar }
20132654012fSReza Sabdar 
20142654012fSReza Sabdar 
20152654012fSReza Sabdar 
20162654012fSReza Sabdar /*
20172654012fSReza Sabdar  * ndmpd_mover_seek
20182654012fSReza Sabdar  *
20192654012fSReza Sabdar  * Seek to the requested data stream position.
20202654012fSReza Sabdar  * If the requested offset is outside of the current window,
20212654012fSReza Sabdar  * the mover is paused and a notify_mover_paused request is sent
20222654012fSReza Sabdar  * notifying the client that a seek is required.
20232654012fSReza Sabdar  * If the requested offest is within the window but not within the
20242654012fSReza Sabdar  * current record, then the tape is positioned to the record containing
20252654012fSReza Sabdar  * the requested offest.
20262654012fSReza Sabdar  * The requested amount of data is then read from the tape device and
20272654012fSReza Sabdar  * written to the data connection.
20282654012fSReza Sabdar  *
20292654012fSReza Sabdar  * Parameters:
20302654012fSReza Sabdar  *   session (input) - session pointer.
20312654012fSReza Sabdar  *   offset  (input) - data stream position to seek to.
20322654012fSReza Sabdar  *   length  (input) - amount of data that will be read.
20332654012fSReza Sabdar  *
20342654012fSReza Sabdar  * Returns:
20352654012fSReza Sabdar  *   1 - seek pending completion by the NDMP client.
20362654012fSReza Sabdar  *   0 - seek successfully completed.
20372654012fSReza Sabdar  *  -1 - error.
20382654012fSReza Sabdar  */
20392654012fSReza Sabdar int
ndmpd_mover_seek(ndmpd_session_t * session,u_longlong_t offset,u_longlong_t length)20402654012fSReza Sabdar ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
20412654012fSReza Sabdar     u_longlong_t length)
20422654012fSReza Sabdar {
20432654012fSReza Sabdar 	int ctlcmd;
20442654012fSReza Sabdar 	int ctlcnt;
20452654012fSReza Sabdar 	u_longlong_t tape_position;
20462654012fSReza Sabdar 	u_longlong_t buf_position;
20472654012fSReza Sabdar 	ndmp_notify_mover_paused_request pause_request;
20482654012fSReza Sabdar 
20492654012fSReza Sabdar 	session->ns_mover.md_seek_position = offset;
20502654012fSReza Sabdar 	session->ns_mover.md_bytes_left_to_read = length;
20512654012fSReza Sabdar 
20522654012fSReza Sabdar 	/*
20532654012fSReza Sabdar 	 * If the requested position is outside of the window,
20542654012fSReza Sabdar 	 * notify the client that a seek is required.
20552654012fSReza Sabdar 	 */
20562654012fSReza Sabdar 	if (session->ns_mover.md_seek_position <
20572654012fSReza Sabdar 	    session->ns_mover.md_window_offset ||
20582654012fSReza Sabdar 	    session->ns_mover.md_seek_position >=
20592654012fSReza Sabdar 	    session->ns_mover.md_window_offset +
20602654012fSReza Sabdar 	    session->ns_mover.md_window_length) {
20612654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
20622654012fSReza Sabdar 		    session->ns_mover.md_seek_position);
20632654012fSReza Sabdar 
20642654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
20652654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
20662654012fSReza Sabdar 
20672654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
20682654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
20692654012fSReza Sabdar 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
20702654012fSReza Sabdar 		pause_request.seek_position = long_long_to_quad(offset);
20712654012fSReza Sabdar 
20722654012fSReza Sabdar 		if (ndmp_send_request(session->ns_connection,
20732654012fSReza Sabdar 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
20742654012fSReza Sabdar 		    (void *) &pause_request, 0) < 0) {
20752654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
20762654012fSReza Sabdar 			    "Sending notify_mover_paused request");
20772654012fSReza Sabdar 			return (-1);
20782654012fSReza Sabdar 		}
20792654012fSReza Sabdar 		return (1);
20802654012fSReza Sabdar 	}
20812654012fSReza Sabdar 	/*
20822654012fSReza Sabdar 	 * Determine the data stream position of the first byte in the
20832654012fSReza Sabdar 	 * data buffer.
20842654012fSReza Sabdar 	 */
20852654012fSReza Sabdar 	buf_position = session->ns_mover.md_position -
20862654012fSReza Sabdar 	    (session->ns_mover.md_position % session->ns_mover.md_record_size);
20872654012fSReza Sabdar 
20882654012fSReza Sabdar 	/*
20892654012fSReza Sabdar 	 * Determine the data stream position of the next byte that
20902654012fSReza Sabdar 	 * will be read from tape.
20912654012fSReza Sabdar 	 */
20922654012fSReza Sabdar 	tape_position = buf_position;
20932654012fSReza Sabdar 	if (session->ns_mover.md_w_index != 0)
20942654012fSReza Sabdar 		tape_position += session->ns_mover.md_record_size;
20952654012fSReza Sabdar 
20962654012fSReza Sabdar 	/*
20972654012fSReza Sabdar 	 * Check if requested position is for data that has been read and is
20982654012fSReza Sabdar 	 * in the buffer.
20992654012fSReza Sabdar 	 */
21002654012fSReza Sabdar 	if (offset >= buf_position && offset < tape_position) {
21012654012fSReza Sabdar 		session->ns_mover.md_position = offset;
21022654012fSReza Sabdar 		session->ns_mover.md_r_index = session->ns_mover.md_position -
21032654012fSReza Sabdar 		    buf_position;
21042654012fSReza Sabdar 
21052654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
21062654012fSReza Sabdar 		    session->ns_mover.md_position,
21072654012fSReza Sabdar 		    session->ns_mover.md_r_index);
21082654012fSReza Sabdar 
21092654012fSReza Sabdar 		return (0);
21102654012fSReza Sabdar 	}
21112654012fSReza Sabdar 
21122654012fSReza Sabdar 	ctlcmd = 0;
21132654012fSReza Sabdar 	if (tape_position > session->ns_mover.md_seek_position) {
21142654012fSReza Sabdar 		/* Need to seek backward. */
21152654012fSReza Sabdar 		ctlcmd = MTBSR;
21162654012fSReza Sabdar 		ctlcnt = (int)((tape_position - offset - 1)
21172654012fSReza Sabdar 		    / session->ns_mover.md_record_size) + 1;
21182654012fSReza Sabdar 		tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
21192654012fSReza Sabdar 		    session->ns_mover.md_record_size) + 1) *
21202654012fSReza Sabdar 		    (u_longlong_t)session->ns_mover.md_record_size);
21212654012fSReza Sabdar 
21222654012fSReza Sabdar 	} else if (offset >= tape_position + session->ns_mover.md_record_size) {
21232654012fSReza Sabdar 		/* Need to seek forward. */
21242654012fSReza Sabdar 		ctlcmd = MTFSR;
21252654012fSReza Sabdar 		ctlcnt = (int)((offset - tape_position)
21262654012fSReza Sabdar 		    / session->ns_mover.md_record_size);
21272654012fSReza Sabdar 		tape_position += ((u_longlong_t)(((offset - tape_position) /
21282654012fSReza Sabdar 		    session->ns_mover.md_record_size)) *
21292654012fSReza Sabdar 		    (u_longlong_t)session->ns_mover.md_record_size);
21302654012fSReza Sabdar 	}
21312654012fSReza Sabdar 	/* Reposition the tape if necessary. */
21322654012fSReza Sabdar 	if (ctlcmd) {
21332654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
21342654012fSReza Sabdar 		    ctlcmd, ctlcnt);
21352654012fSReza Sabdar 		(void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
21362654012fSReza Sabdar 	}
21372654012fSReza Sabdar 
21382654012fSReza Sabdar 	session->ns_mover.md_position = tape_position;
21392654012fSReza Sabdar 	session->ns_mover.md_r_index = 0;
21402654012fSReza Sabdar 	session->ns_mover.md_w_index = 0;
21412654012fSReza Sabdar 
21422654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
21432654012fSReza Sabdar 
21442654012fSReza Sabdar 	return (0);
21452654012fSReza Sabdar }
21462654012fSReza Sabdar 
21472654012fSReza Sabdar 
21482654012fSReza Sabdar /* ** static functions ************************************************** */
21492654012fSReza Sabdar 
21502654012fSReza Sabdar /*
21512654012fSReza Sabdar  * create_listen_socket_v2
21522654012fSReza Sabdar  *
21532654012fSReza Sabdar  * Creates a socket for listening for accepting data connections.
21542654012fSReza Sabdar  *
21552654012fSReza Sabdar  * Parameters:
21562654012fSReza Sabdar  *   session (input)  - session pointer.
21572654012fSReza Sabdar  *   addr    (output) - location to store address of socket.
21582654012fSReza Sabdar  *   port    (output) - location to store port of socket.
21592654012fSReza Sabdar  *
21602654012fSReza Sabdar  * Returns:
21612654012fSReza Sabdar  *   0 - success.
21622654012fSReza Sabdar  *  -1 - error.
21632654012fSReza Sabdar  */
21642654012fSReza Sabdar static int
create_listen_socket_v2(ndmpd_session_t * session,ulong_t * addr,ushort_t * port)21652654012fSReza Sabdar create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
21662654012fSReza Sabdar {
21672654012fSReza Sabdar 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
21682654012fSReza Sabdar 	if (session->ns_mover.md_listen_sock < 0)
21692654012fSReza Sabdar 		return (-1);
21702654012fSReza Sabdar 
21712654012fSReza Sabdar 	/*
21722654012fSReza Sabdar 	 * Add a file handler for the listen socket.
21732654012fSReza Sabdar 	 * ndmpd_select will call accept_connection when a
21742654012fSReza Sabdar 	 * connection is ready to be accepted.
21752654012fSReza Sabdar 	 */
21762654012fSReza Sabdar 	if (ndmpd_add_file_handler(session, (void *) session,
21772654012fSReza Sabdar 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
21782654012fSReza Sabdar 	    accept_connection) < 0) {
21792654012fSReza Sabdar 		(void) close(session->ns_mover.md_listen_sock);
21802654012fSReza Sabdar 		session->ns_mover.md_listen_sock = -1;
21812654012fSReza Sabdar 		return (-1);
21822654012fSReza Sabdar 	}
21832654012fSReza Sabdar 
21842654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
21852654012fSReza Sabdar 	return (0);
21862654012fSReza Sabdar }
21872654012fSReza Sabdar 
21882654012fSReza Sabdar /*
21892654012fSReza Sabdar  * accept_connection
21902654012fSReza Sabdar  *
21912654012fSReza Sabdar  * Accept a data connection from a data server.
21922654012fSReza Sabdar  * Called by ndmpd_select when a connection is pending on
21932654012fSReza Sabdar  * the mover listen socket.
21942654012fSReza Sabdar  *
21952654012fSReza Sabdar  * Parameters:
21962654012fSReza Sabdar  *   cookie  (input) - session pointer.
21972654012fSReza Sabdar  *   fd      (input) - file descriptor.
21982654012fSReza Sabdar  *   mode    (input) - select mode.
21992654012fSReza Sabdar  *
22002654012fSReza Sabdar  * Returns:
22012654012fSReza Sabdar  *   void.
22022654012fSReza Sabdar  */
22032654012fSReza Sabdar /*ARGSUSED*/
22042654012fSReza Sabdar static void
accept_connection(void * cookie,int fd,ulong_t mode)22052654012fSReza Sabdar accept_connection(void *cookie, int fd, ulong_t mode)
22062654012fSReza Sabdar {
22072654012fSReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
22082654012fSReza Sabdar 	struct sockaddr_in from;
22092654012fSReza Sabdar 	int from_len;
22102654012fSReza Sabdar 
22112654012fSReza Sabdar 	from_len = sizeof (from);
22122654012fSReza Sabdar 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
22132654012fSReza Sabdar 	    &from_len);
22142654012fSReza Sabdar 
22152654012fSReza Sabdar 	(void) ndmpd_remove_file_handler(session, fd);
22162654012fSReza Sabdar 	(void) close(session->ns_mover.md_listen_sock);
22172654012fSReza Sabdar 	session->ns_mover.md_listen_sock = -1;
22182654012fSReza Sabdar 
22192654012fSReza Sabdar 	if (session->ns_mover.md_sock < 0) {
22202654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
22212654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
22222654012fSReza Sabdar 		return;
22232654012fSReza Sabdar 	}
222497f7c475SJan Kryl 	set_socket_options(session->ns_mover.md_sock);
22252654012fSReza Sabdar 
22262654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
22272654012fSReza Sabdar 
22282654012fSReza Sabdar 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
22292654012fSReza Sabdar 		if (start_mover_for_backup(session) < 0) {
22302654012fSReza Sabdar 			ndmpd_mover_error(session,
22312654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
22322654012fSReza Sabdar 			return;
22332654012fSReza Sabdar 		}
22342654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
22352654012fSReza Sabdar 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
22362654012fSReza Sabdar 		    ntohs(from.sin_port));
22372654012fSReza Sabdar 	} else {
22382654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
22392654012fSReza Sabdar 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
22402654012fSReza Sabdar 		    ntohs(from.sin_port));
22412654012fSReza Sabdar 	}
22422654012fSReza Sabdar 
22432654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "Received connection");
22442654012fSReza Sabdar 
22452654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
22462654012fSReza Sabdar }
22472654012fSReza Sabdar 
22482654012fSReza Sabdar /*
22492654012fSReza Sabdar  * tape_read
22502654012fSReza Sabdar  *
22512654012fSReza Sabdar  * Reads a data record from tape. Detects and handles EOT conditions.
22522654012fSReza Sabdar  *
22532654012fSReza Sabdar  * Parameters:
22542654012fSReza Sabdar  *   session (input) - session pointer.
22552654012fSReza Sabdar  *   data    (input) - location to read data to.
22562654012fSReza Sabdar  *
22572654012fSReza Sabdar  * Returns:
22582654012fSReza Sabdar  *    0 - operation aborted.
22592654012fSReza Sabdar  *   -1 - tape read error.
22602654012fSReza Sabdar  *   otherwise - number of bytes read.
22612654012fSReza Sabdar  */
22622654012fSReza Sabdar static int
tape_read(ndmpd_session_t * session,char * data)22632654012fSReza Sabdar tape_read(ndmpd_session_t *session, char *data)
22642654012fSReza Sabdar {
22652654012fSReza Sabdar 	ssize_t n;
22662654012fSReza Sabdar 	int err;
22672654012fSReza Sabdar 	int count = session->ns_mover.md_record_size;
22682654012fSReza Sabdar 
22692654012fSReza Sabdar 	for (; ; ) {
22702654012fSReza Sabdar 		n = read(session->ns_tape.td_fd, data, count);
22712654012fSReza Sabdar 		if (n < 0) {
22722654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
22732654012fSReza Sabdar 			return (TAPE_READ_ERR);
22742654012fSReza Sabdar 		}
22752654012fSReza Sabdar 		NS_ADD(rtape, n);
22762654012fSReza Sabdar 
22772654012fSReza Sabdar 		if (n == 0) {
22782654012fSReza Sabdar 			if (!is_writer_running(session))
22792654012fSReza Sabdar 				return (TAPE_NO_WRITER_ERR);
22802654012fSReza Sabdar 
22812654012fSReza Sabdar 			/*
22822654012fSReza Sabdar 			 * End of media reached.
22832654012fSReza Sabdar 			 * Notify client and wait for the client to
22842654012fSReza Sabdar 			 * either abort the data operation or continue the
22852654012fSReza Sabdar 			 * operation after changing the tape.
22862654012fSReza Sabdar 			 */
22872654012fSReza Sabdar 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
22882654012fSReza Sabdar 			    ++ndmp_log_msg_id,
22892654012fSReza Sabdar 			    "End of tape reached. Load next tape");
22902654012fSReza Sabdar 
22912654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
22922654012fSReza Sabdar 			    "End of tape reached. Load next tape");
22932654012fSReza Sabdar 
22942654012fSReza Sabdar 			err = change_tape(session);
22952654012fSReza Sabdar 
22962654012fSReza Sabdar 			/* Operation aborted or connection terminated? */
22972654012fSReza Sabdar 			if (err < 0) {
22982654012fSReza Sabdar 				/*
22992654012fSReza Sabdar 				 * K.L. Go back one record if it is read
23002654012fSReza Sabdar 				 * but not used.
23012654012fSReza Sabdar 				 */
23022654012fSReza Sabdar 
23032654012fSReza Sabdar 				if (count != session->ns_mover.md_record_size) {
23042654012fSReza Sabdar 					(void) ndmp_mtioctl(
23052654012fSReza Sabdar 					    session->ns_tape.td_fd, MTBSR, 1);
23062654012fSReza Sabdar 				}
23072654012fSReza Sabdar 				return (0);
23082654012fSReza Sabdar 			}
23092654012fSReza Sabdar 			/* Retry the read from the new tape. */
23102654012fSReza Sabdar 			continue;
23112654012fSReza Sabdar 		}
23122654012fSReza Sabdar 
23132654012fSReza Sabdar 		/* Change to pass Veritas Netbackup prequal test. */
23142654012fSReza Sabdar 		data += n;
23152654012fSReza Sabdar 		count -= n;
23162654012fSReza Sabdar 		if (count <= 0) {
23172654012fSReza Sabdar 			session->ns_mover.md_record_num++;
23182654012fSReza Sabdar 			session->ns_tape.td_record_count++;
23192654012fSReza Sabdar 			return (n);
23202654012fSReza Sabdar 		}
23212654012fSReza Sabdar 	}
23222654012fSReza Sabdar }
23232654012fSReza Sabdar 
23242654012fSReza Sabdar /*
23252654012fSReza Sabdar  * change_tape
23262654012fSReza Sabdar  *
23272654012fSReza Sabdar  * Send a notify_pause request (protocol version 1) or
23282654012fSReza Sabdar  * notify_mover_pause request (protocol version 2) to the
23292654012fSReza Sabdar  * NDMP client to inform
23302654012fSReza Sabdar  * the client that a tape volume change is required.
23312654012fSReza Sabdar  * Process messages until the data/mover operation is either aborted
23322654012fSReza Sabdar  * or continued.
23332654012fSReza Sabdar  *
23342654012fSReza Sabdar  * Parameters:
23352654012fSReza Sabdar  *   client_data (input) - session pointer.
23362654012fSReza Sabdar  *
23372654012fSReza Sabdar  * Returns:
23382654012fSReza Sabdar  *   0 - operation has been continued.
23392654012fSReza Sabdar  *  -1 - operation has been aborted.
23402654012fSReza Sabdar  */
23412654012fSReza Sabdar static int
change_tape(ndmpd_session_t * session)23422654012fSReza Sabdar change_tape(ndmpd_session_t *session)
23432654012fSReza Sabdar {
23442654012fSReza Sabdar 	ndmp_notify_mover_paused_request request;
23452654012fSReza Sabdar 
23462654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
23472654012fSReza Sabdar 
23482654012fSReza Sabdar 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
23492654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
23502654012fSReza Sabdar 	else
23512654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
23522654012fSReza Sabdar 
23532654012fSReza Sabdar 	request.reason = session->ns_mover.md_pause_reason;
23542654012fSReza Sabdar 	request.seek_position = long_long_to_quad(0LL);
23552654012fSReza Sabdar 
23562654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
23572654012fSReza Sabdar 	    session->ns_mover.md_pause_reason);
23582654012fSReza Sabdar 
23592654012fSReza Sabdar 	if (ndmp_send_request(session->ns_connection,
23602654012fSReza Sabdar 	    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
23612654012fSReza Sabdar 	    (void *) &request, 0) < 0) {
23622654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
23632654012fSReza Sabdar 		    "Sending notify_mover_paused request");
23642654012fSReza Sabdar 		return (-1);
23652654012fSReza Sabdar 	}
23662654012fSReza Sabdar 	/*
23672654012fSReza Sabdar 	 * Wait for until the state is changed by
23682654012fSReza Sabdar 	 * an abort or continue request.
23692654012fSReza Sabdar 	 */
2370a23888a3SJan Kryl 	return (ndmp_wait_for_mover(session));
23712654012fSReza Sabdar }
23722654012fSReza Sabdar 
23732654012fSReza Sabdar 
23742654012fSReza Sabdar /*
23752654012fSReza Sabdar  * discard_data
23762654012fSReza Sabdar  *
23772654012fSReza Sabdar  * Read and discard data from the data connection.
23782654012fSReza Sabdar  * Called when a module has called ndmpd_seek() prior to
23792654012fSReza Sabdar  * reading all of the data from the previous seek.
23802654012fSReza Sabdar  *
23812654012fSReza Sabdar  * Parameters:
23822654012fSReza Sabdar  *   session (input) - session pointer.
23832654012fSReza Sabdar  *
23842654012fSReza Sabdar  * Returns:
23852654012fSReza Sabdar  *   number of bytes read and discarded.
23862654012fSReza Sabdar  *  -1 - error.
23872654012fSReza Sabdar  */
23882654012fSReza Sabdar static int
discard_data(ndmpd_session_t * session,ulong_t length)23892654012fSReza Sabdar discard_data(ndmpd_session_t *session, ulong_t length)
23902654012fSReza Sabdar {
23912654012fSReza Sabdar 	int n;
23922654012fSReza Sabdar 	char *addr;
23932654012fSReza Sabdar 
23942654012fSReza Sabdar 	if ((addr = ndmp_malloc(length)) == NULL)
23952654012fSReza Sabdar 		return (-1);
23962654012fSReza Sabdar 
23972654012fSReza Sabdar 	/* Read and discard the data. */
23982654012fSReza Sabdar 	n = read(session->ns_mover.md_sock, addr, length);
23992654012fSReza Sabdar 	if (n < 0) {
24002654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
24012654012fSReza Sabdar 		free(addr);
24022654012fSReza Sabdar 		return (-1);
24032654012fSReza Sabdar 	}
24042654012fSReza Sabdar 
24052654012fSReza Sabdar 	free(addr);
24062654012fSReza Sabdar 	return (n);
24072654012fSReza Sabdar }
24082654012fSReza Sabdar 
24092654012fSReza Sabdar 
24102654012fSReza Sabdar /*
24112654012fSReza Sabdar  * mover_tape_read_one_buf
24122654012fSReza Sabdar  *
24132654012fSReza Sabdar  * Read one buffer from the tape. This is used by mover_tape_reader
24142654012fSReza Sabdar  *
24152654012fSReza Sabdar  * Parameters:
24162654012fSReza Sabdar  *   session (input) - session pointer.
24172654012fSReza Sabdar  *   buf (input) - buffer read
24182654012fSReza Sabdar  *
24192654012fSReza Sabdar  * Returns:
24202654012fSReza Sabdar  *   0: on success
24212654012fSReza Sabdar  *  -1: otherwise
24222654012fSReza Sabdar  */
24232654012fSReza Sabdar static int
mover_tape_read_one_buf(ndmpd_session_t * session,tlm_buffer_t * buf)24242654012fSReza Sabdar mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
24252654012fSReza Sabdar {
24262654012fSReza Sabdar 	int n;
24272654012fSReza Sabdar 
24282654012fSReza Sabdar 	tlm_buffer_mark_empty(buf);
24292654012fSReza Sabdar 
24302654012fSReza Sabdar 	/*
24312654012fSReza Sabdar 	 * If the end of the mover window has been reached,
24322654012fSReza Sabdar 	 * then notify the client that a seek is needed.
24332654012fSReza Sabdar 	 * Remove the file handler to prevent this function from
24342654012fSReza Sabdar 	 * being called. The handler will be reinstalled in
24352654012fSReza Sabdar 	 * ndmpd_mover_continue.
24362654012fSReza Sabdar 	 */
24372654012fSReza Sabdar 
24382654012fSReza Sabdar 	if (session->ns_mover.md_position >=
24392654012fSReza Sabdar 	    session->ns_mover.md_window_offset +
24402654012fSReza Sabdar 	    session->ns_mover.md_window_length) {
24412654012fSReza Sabdar 		ndmp_notify_mover_paused_request pause_request;
24422654012fSReza Sabdar 
24432654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "end of mover window");
24442654012fSReza Sabdar 
24452654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
24462654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
24472654012fSReza Sabdar 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
24482654012fSReza Sabdar 		pause_request.seek_position =
24492654012fSReza Sabdar 		    long_long_to_quad(session->ns_mover.md_position);
24502654012fSReza Sabdar 
24512654012fSReza Sabdar 		if (ndmp_send_request(session->ns_connection,
24522654012fSReza Sabdar 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
24532654012fSReza Sabdar 		    (void *) &pause_request, 0) < 0) {
24542654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
24552654012fSReza Sabdar 			    "Sending notify_mover_paused request");
24562654012fSReza Sabdar 			ndmpd_mover_error(session,
24572654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
24582654012fSReza Sabdar 		}
24592654012fSReza Sabdar 		buf->tb_errno = EIO;
24602654012fSReza Sabdar 		return (TAPE_READ_ERR);
24612654012fSReza Sabdar 	}
24622654012fSReza Sabdar 
24632654012fSReza Sabdar 	n = tape_read(session, buf->tb_buffer_data);
24642654012fSReza Sabdar 
24652654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
24662654012fSReza Sabdar 
24672654012fSReza Sabdar 	if (n <= 0) {
24682654012fSReza Sabdar 		if (n < 0)
24692654012fSReza Sabdar 			ndmpd_mover_error(session,
24702654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
24712654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
24722654012fSReza Sabdar 		return (TAPE_READ_ERR);
24732654012fSReza Sabdar 	}
24742654012fSReza Sabdar 
24752654012fSReza Sabdar 	buf->tb_full = TRUE;
24762654012fSReza Sabdar 	buf->tb_buffer_size = session->ns_mover.md_record_size;
24772654012fSReza Sabdar 
24782654012fSReza Sabdar 	/*
24792654012fSReza Sabdar 	 * Discard data if the current data stream position is
24802654012fSReza Sabdar 	 * prior to the seek position. This is necessary if a seek
24812654012fSReza Sabdar 	 * request set the seek pointer to a position that is not a
24822654012fSReza Sabdar 	 * record boundary. The seek request handler can only position
24832654012fSReza Sabdar 	 * to the start of a record.
24842654012fSReza Sabdar 	 */
24852654012fSReza Sabdar 	if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
24862654012fSReza Sabdar 		session->ns_mover.md_position =
24872654012fSReza Sabdar 		    session->ns_mover.md_seek_position;
24882654012fSReza Sabdar 
24892654012fSReza Sabdar 	return (0);
24902654012fSReza Sabdar }
24912654012fSReza Sabdar 
24922654012fSReza Sabdar 
24932654012fSReza Sabdar /*
24942654012fSReza Sabdar  * mover_tape_reader
24952654012fSReza Sabdar  *
24962654012fSReza Sabdar  * Mover tape reader thread. It is launched when the mover is started
24972654012fSReza Sabdar  * for restore.
24982654012fSReza Sabdar  *
24992654012fSReza Sabdar  * Parameters:
25002654012fSReza Sabdar  *   session (input) - session pointer.
25012654012fSReza Sabdar  *
25022654012fSReza Sabdar  * Returns:
25032654012fSReza Sabdar  *   0: on success
25042654012fSReza Sabdar  *  -1: otherwise
25052654012fSReza Sabdar  */
2506*82049ff5SToomas Soome void *
mover_tape_reader(void * ptr)2507*82049ff5SToomas Soome mover_tape_reader(void *ptr)
25082654012fSReza Sabdar {
25092654012fSReza Sabdar 	int bidx;	/* buffer index */
25102654012fSReza Sabdar 	int rv;
25112654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
25122654012fSReza Sabdar 	tlm_buffer_t *buf;
25132654012fSReza Sabdar 	tlm_buffers_t *bufs;
25142654012fSReza Sabdar 	tlm_cmd_t *lcmd;	/* Local command */
25152654012fSReza Sabdar 	tlm_commands_t *cmds;	/* Commands structure */
2516*82049ff5SToomas Soome 	ndmpd_session_t *session = ptr;
25172654012fSReza Sabdar 
25182654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
25192654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2520*82049ff5SToomas Soome 		return ((void *)(uintptr_t)-1);
25212654012fSReza Sabdar 	}
25222654012fSReza Sabdar 
25232654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
25242654012fSReza Sabdar 	lcmd = cmds->tcs_command;
25252654012fSReza Sabdar 	bufs = lcmd->tc_buffers;
25262654012fSReza Sabdar 
25272654012fSReza Sabdar 	lcmd->tc_ref++;
25282654012fSReza Sabdar 	cmds->tcs_reader_count++;
25292654012fSReza Sabdar 
25302654012fSReza Sabdar 	/*
25312654012fSReza Sabdar 	 * Let our parent thread know that we are running.
25322654012fSReza Sabdar 	 */
25332654012fSReza Sabdar 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
25342654012fSReza Sabdar 
25352654012fSReza Sabdar 	buf = tlm_buffer_in_buf(bufs, &bidx);
25362654012fSReza Sabdar 	while (cmds->tcs_reader == TLM_RESTORE_RUN &&
25372654012fSReza Sabdar 	    lcmd->tc_reader == TLM_RESTORE_RUN) {
25382654012fSReza Sabdar 		buf = tlm_buffer_in_buf(bufs, NULL);
25392654012fSReza Sabdar 
25402654012fSReza Sabdar 		if (buf->tb_full) {
25412654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
25422654012fSReza Sabdar 			/*
25432654012fSReza Sabdar 			 * The buffer is still full, wait for the consumer
25442654012fSReza Sabdar 			 * thread to use it.
25452654012fSReza Sabdar 			 */
25462654012fSReza Sabdar 			tlm_buffer_out_buf_timed_wait(bufs, 100);
25472654012fSReza Sabdar 
25482654012fSReza Sabdar 		} else {
25492654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "r%d", bidx);
25502654012fSReza Sabdar 
25512654012fSReza Sabdar 			rv = mover_tape_read_one_buf(session, buf);
25522654012fSReza Sabdar 			/*
25532654012fSReza Sabdar 			 * If there was an error while reading, such as
25542654012fSReza Sabdar 			 * end of stream.
25552654012fSReza Sabdar 			 */
25562654012fSReza Sabdar 			if (rv < 0) {
25572654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
25582654012fSReza Sabdar 				break;
25592654012fSReza Sabdar 			}
25602654012fSReza Sabdar 
25612654012fSReza Sabdar 			/*
25622654012fSReza Sabdar 			 * Can we do more buffering?
25632654012fSReza Sabdar 			 */
25642654012fSReza Sabdar 			if (is_buffer_erroneous(buf)) {
25652654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
25662654012fSReza Sabdar 				    "Exiting, errno: %d, eot: %d, eof: %d",
25672654012fSReza Sabdar 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
25682654012fSReza Sabdar 				break;
25692654012fSReza Sabdar 			}
25702654012fSReza Sabdar 
25712654012fSReza Sabdar 			(void) tlm_buffer_advance_in_idx(bufs);
25722654012fSReza Sabdar 			tlm_buffer_release_in_buf(bufs);
25732654012fSReza Sabdar 			bidx = bufs->tbs_buffer_in;
25742654012fSReza Sabdar 		}
25752654012fSReza Sabdar 	}
25762654012fSReza Sabdar 
25772654012fSReza Sabdar 	/* If the consumer is waiting for us, wake it up. */
25782654012fSReza Sabdar 	tlm_buffer_release_in_buf(bufs);
25792654012fSReza Sabdar 
25802654012fSReza Sabdar 	/*
25812654012fSReza Sabdar 	 * Clean up.
25822654012fSReza Sabdar 	 */
25832654012fSReza Sabdar 	cmds->tcs_reader_count--;
25842654012fSReza Sabdar 	lcmd->tc_ref--;
25852654012fSReza Sabdar 	lcmd->tc_writer = TLM_STOP;
2586*82049ff5SToomas Soome 	return (NULL);
25872654012fSReza Sabdar }
25882654012fSReza Sabdar 
25892654012fSReza Sabdar 
25902654012fSReza Sabdar /*
25912654012fSReza Sabdar  * mover_socket_write_one_buf
25922654012fSReza Sabdar  *
25932654012fSReza Sabdar  * Write one buffer to the network socket. This is used by mover_socket_writer
25942654012fSReza Sabdar  *
25952654012fSReza Sabdar  * Parameters:
25962654012fSReza Sabdar  *   session (input) - session pointer.
25972654012fSReza Sabdar  *   buf (input) - buffer read
25982654012fSReza Sabdar  *
25992654012fSReza Sabdar  * Returns:
26002654012fSReza Sabdar  *   0: on success
26012654012fSReza Sabdar  *  -1: otherwise
26022654012fSReza Sabdar  */
26032654012fSReza Sabdar static int
mover_socket_write_one_buf(ndmpd_session_t * session,tlm_buffer_t * buf)26042654012fSReza Sabdar mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
26052654012fSReza Sabdar {
26062654012fSReza Sabdar 	int n;
26072654012fSReza Sabdar 
26082654012fSReza Sabdar 	/* Write the data to the data connection. */
26092654012fSReza Sabdar 	errno = 0;
26102654012fSReza Sabdar 	n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
26112654012fSReza Sabdar 	    buf->tb_buffer_size);
26122654012fSReza Sabdar 
26132654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
26142654012fSReza Sabdar 
26152654012fSReza Sabdar 	if (n < 0) {
26162654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
26172654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
26182654012fSReza Sabdar 		return (-1);
26192654012fSReza Sabdar 	}
26202654012fSReza Sabdar 
26212654012fSReza Sabdar 	session->ns_mover.md_position += n;
26222654012fSReza Sabdar 	session->ns_mover.md_bytes_left_to_read -= n;
26232654012fSReza Sabdar 	tlm_buffer_mark_empty(buf);
26242654012fSReza Sabdar 
26252654012fSReza Sabdar 	/*
26262654012fSReza Sabdar 	 * If the read limit has been reached,
26272654012fSReza Sabdar 	 * then remove the file handler to prevent this
26282654012fSReza Sabdar 	 * function from getting called. The next mover_read request
26292654012fSReza Sabdar 	 * will reinstall the handler.
26302654012fSReza Sabdar 	 */
26312654012fSReza Sabdar 	if (session->ns_mover.md_bytes_left_to_read == 0) {
26322654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
26332654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
26342654012fSReza Sabdar 		    session->ns_mover.md_sock);
26352654012fSReza Sabdar 		return (-1);
26362654012fSReza Sabdar 	}
26372654012fSReza Sabdar 
26382654012fSReza Sabdar 	return (0);
26392654012fSReza Sabdar }
26402654012fSReza Sabdar 
26412654012fSReza Sabdar 
26422654012fSReza Sabdar 
26432654012fSReza Sabdar /*
26442654012fSReza Sabdar  * mover_socket_writer
26452654012fSReza Sabdar  *
26462654012fSReza Sabdar  * Mover's socket writer thread. This thread sends the read buffer
26472654012fSReza Sabdar  * from the tape to the data server through the network socket.
26482654012fSReza Sabdar  *
26492654012fSReza Sabdar  * Parameters:
26502654012fSReza Sabdar  *   session (input) - session pointer.
26512654012fSReza Sabdar  *
26522654012fSReza Sabdar  * Returns:
26532654012fSReza Sabdar  *   0: on success
26542654012fSReza Sabdar  *  -1: otherwise
26552654012fSReza Sabdar  */
2656*82049ff5SToomas Soome void *
mover_socket_writer(void * ptr)2657*82049ff5SToomas Soome mover_socket_writer(void *ptr)
26582654012fSReza Sabdar {
26592654012fSReza Sabdar 	int bidx;	/* buffer index */
26602654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
26612654012fSReza Sabdar 	tlm_buffer_t *buf;
26622654012fSReza Sabdar 	tlm_buffers_t *bufs;
26632654012fSReza Sabdar 	tlm_cmd_t *lcmd;	/* Local command */
26642654012fSReza Sabdar 	tlm_commands_t *cmds;	/* Commands structure */
2665*82049ff5SToomas Soome 	ndmpd_session_t *session = ptr;
26662654012fSReza Sabdar 
26672654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
26682654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2669*82049ff5SToomas Soome 		return ((void *)(uintptr_t)-1);
26702654012fSReza Sabdar 	}
26712654012fSReza Sabdar 
26722654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
26732654012fSReza Sabdar 	lcmd = cmds->tcs_command;
26742654012fSReza Sabdar 	bufs = lcmd->tc_buffers;
26752654012fSReza Sabdar 
26762654012fSReza Sabdar 	lcmd->tc_ref++;
26772654012fSReza Sabdar 	cmds->tcs_writer_count++;
26782654012fSReza Sabdar 
26792654012fSReza Sabdar 	/*
26802654012fSReza Sabdar 	 * Let our parent thread know that we are running.
26812654012fSReza Sabdar 	 */
26822654012fSReza Sabdar 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
26832654012fSReza Sabdar 
26842654012fSReza Sabdar 	bidx = bufs->tbs_buffer_out;
26852654012fSReza Sabdar 	while (cmds->tcs_writer != (int)TLM_ABORT &&
26862654012fSReza Sabdar 	    lcmd->tc_writer != (int)TLM_ABORT) {
26872654012fSReza Sabdar 		buf = &bufs->tbs_buffer[bidx];
26882654012fSReza Sabdar 
26892654012fSReza Sabdar 		if (buf->tb_full) {
26902654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "w%d", bidx);
26912654012fSReza Sabdar 
26922654012fSReza Sabdar 			if (mover_socket_write_one_buf(session, buf) < 0) {
26932654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
26942654012fSReza Sabdar 				    "mover_socket_write_one_buf() < 0");
26952654012fSReza Sabdar 				break;
26962654012fSReza Sabdar 			}
26972654012fSReza Sabdar 
26982654012fSReza Sabdar 			(void) tlm_buffer_advance_out_idx(bufs);
26992654012fSReza Sabdar 			tlm_buffer_release_out_buf(bufs);
27002654012fSReza Sabdar 			bidx = bufs->tbs_buffer_out;
27012654012fSReza Sabdar 		} else {
27022654012fSReza Sabdar 			if (lcmd->tc_writer != TLM_RESTORE_RUN) {
27032654012fSReza Sabdar 				/* No more data is coming, time to exit */
27042654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Time to exit");
27052654012fSReza Sabdar 				break;
27062654012fSReza Sabdar 			}
27072654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
27082654012fSReza Sabdar 			/*
27092654012fSReza Sabdar 			 * The buffer is not full, wait for the producer
27102654012fSReza Sabdar 			 * thread to fill it.
27112654012fSReza Sabdar 			 */
271286c48bbfSReza Sabdar 			tlm_buffer_in_buf_timed_wait(bufs, 100);
27132654012fSReza Sabdar 		}
27142654012fSReza Sabdar 	}
27152654012fSReza Sabdar 
27162654012fSReza Sabdar 	if (cmds->tcs_writer == (int)TLM_ABORT)
27172654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
27182654012fSReza Sabdar 	if (lcmd->tc_writer == (int)TLM_ABORT)
27192654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
27202654012fSReza Sabdar 
27212654012fSReza Sabdar 	/* If the producer is waiting for us, wake it up. */
27222654012fSReza Sabdar 	tlm_buffer_release_out_buf(bufs);
27232654012fSReza Sabdar 
27242654012fSReza Sabdar 	/*
27252654012fSReza Sabdar 	 * Clean up.
27262654012fSReza Sabdar 	 */
27272654012fSReza Sabdar 	cmds->tcs_writer_count--;
27282654012fSReza Sabdar 	lcmd->tc_ref--;
27292654012fSReza Sabdar 	lcmd->tc_reader = TLM_STOP;
2730*82049ff5SToomas Soome 	return (NULL);
27312654012fSReza Sabdar }
27322654012fSReza Sabdar 
27332654012fSReza Sabdar 
27342654012fSReza Sabdar /*
27352654012fSReza Sabdar  * start_mover_for_restore
27362654012fSReza Sabdar  *
27372654012fSReza Sabdar  * Creates the mover tape reader and network writer threads for
27382654012fSReza Sabdar  * the mover to perform the 3-way restore.
27392654012fSReza Sabdar  *
27402654012fSReza Sabdar  * Parameters:
27412654012fSReza Sabdar  *   session (input) - session pointer.
27422654012fSReza Sabdar  *
27432654012fSReza Sabdar  * Returns:
27442654012fSReza Sabdar  *   0: on success
27452654012fSReza Sabdar  *  -1: otherwise
27462654012fSReza Sabdar  */
27472654012fSReza Sabdar static int
start_mover_for_restore(ndmpd_session_t * session)27482654012fSReza Sabdar start_mover_for_restore(ndmpd_session_t *session)
27492654012fSReza Sabdar {
27502654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
27512654012fSReza Sabdar 	tlm_commands_t *cmds;
27522654012fSReza Sabdar 	long xfer_size;
27532654012fSReza Sabdar 	int rc;
27542654012fSReza Sabdar 
27552654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
27562654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
27572654012fSReza Sabdar 		return (-1);
27582654012fSReza Sabdar 	}
27592654012fSReza Sabdar 
27602654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
27612654012fSReza Sabdar 	(void) memset(cmds, 0, sizeof (*cmds));
27622654012fSReza Sabdar 	cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
27632654012fSReza Sabdar 	xfer_size = ndmp_buffer_get_size(session);
27642654012fSReza Sabdar 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
27652654012fSReza Sabdar 	if (cmds->tcs_command == NULL)
27662654012fSReza Sabdar 		return (-1);
27672654012fSReza Sabdar 
27682654012fSReza Sabdar 	cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
27692654012fSReza Sabdar 	cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
27702654012fSReza Sabdar 
27712654012fSReza Sabdar 	/*
27722654012fSReza Sabdar 	 * We intentionnally don't wait for the threads to start since the
27732654012fSReza Sabdar 	 * reply of the request (which resulted in calling this function)
27742654012fSReza Sabdar 	 * must be sent to the client before probable errors are sent
27752654012fSReza Sabdar 	 * to the client.
27762654012fSReza Sabdar 	 */
2777*82049ff5SToomas Soome 	rc = pthread_create(NULL, NULL, mover_tape_reader, session);
27782654012fSReza Sabdar 	if (rc == 0) {
27792654012fSReza Sabdar 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
27802654012fSReza Sabdar 	} else {
27812654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
27822654012fSReza Sabdar 		    strerror(rc));
27832654012fSReza Sabdar 		return (-1);
27842654012fSReza Sabdar 	}
27852654012fSReza Sabdar 
2786*82049ff5SToomas Soome 	rc = pthread_create(NULL, NULL, mover_socket_writer, session);
27872654012fSReza Sabdar 	if (rc == 0) {
27882654012fSReza Sabdar 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
27892654012fSReza Sabdar 	} else {
27902654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
27912654012fSReza Sabdar 		    strerror(rc));
27922654012fSReza Sabdar 		return (-1);
27932654012fSReza Sabdar 	}
27942654012fSReza Sabdar 
27952654012fSReza Sabdar 	tlm_release_reader_writer_ipc(cmds->tcs_command);
27962654012fSReza Sabdar 	return (0);
27972654012fSReza Sabdar }
27982654012fSReza Sabdar 
27992654012fSReza Sabdar 
28002654012fSReza Sabdar /*
28012654012fSReza Sabdar  * mover_socket_read_one_buf
28022654012fSReza Sabdar  *
28032654012fSReza Sabdar  * Read one buffer from the network socket for the mover. This is used
28042654012fSReza Sabdar  * by mover_socket_reader
28052654012fSReza Sabdar  *
28062654012fSReza Sabdar  * Parameters:
28072654012fSReza Sabdar  *   session (input) - session pointer.
28082654012fSReza Sabdar  *   buf (input) - buffer read
28092654012fSReza Sabdar  *   read_size (input) - size to be read
28102654012fSReza Sabdar  *
28112654012fSReza Sabdar  * Returns:
28122654012fSReza Sabdar  *   0: on success
28132654012fSReza Sabdar  *  -1: otherwise
28142654012fSReza Sabdar  */
28152654012fSReza Sabdar static int
mover_socket_read_one_buf(ndmpd_session_t * session,tlm_buffer_t * buf,long read_size)28162654012fSReza Sabdar mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
28172654012fSReza Sabdar     long read_size)
28182654012fSReza Sabdar {
28192654012fSReza Sabdar 	int n, index;
28202654012fSReza Sabdar 	long toread;
28212654012fSReza Sabdar 
28222654012fSReza Sabdar 	tlm_buffer_mark_empty(buf);
28232654012fSReza Sabdar 	for (index = 0, toread = read_size; toread > 0; ) {
28242654012fSReza Sabdar 		errno = 0;
28252654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
28262654012fSReza Sabdar 
28272654012fSReza Sabdar 		n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
28282654012fSReza Sabdar 		    toread);
28292654012fSReza Sabdar 		if (n == 0) {
28302654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
28312654012fSReza Sabdar 			break;
28322654012fSReza Sabdar 		} else if (n > 0) {
28332654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
28342654012fSReza Sabdar 			index += n;
28352654012fSReza Sabdar 			toread -= n;
28362654012fSReza Sabdar 		} else {
28372654012fSReza Sabdar 			buf->tb_eof = TRUE;
28382654012fSReza Sabdar 			buf->tb_errno = errno;
28392654012fSReza Sabdar 			buf->tb_buffer_size = 0;
28402654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
28412654012fSReza Sabdar 			return (-1);
28422654012fSReza Sabdar 		}
28432654012fSReza Sabdar 	}
28442654012fSReza Sabdar 
28452654012fSReza Sabdar 	if (index > 0) {
28462654012fSReza Sabdar 		buf->tb_full = TRUE;
28472654012fSReza Sabdar 		buf->tb_buffer_size = read_size;
28482654012fSReza Sabdar 		if (read_size > 0)
28492654012fSReza Sabdar 			(void) memset(&buf->tb_buffer_data[index], 0,
28502654012fSReza Sabdar 			    read_size - index);
28512654012fSReza Sabdar 	} else {
28522654012fSReza Sabdar 		buf->tb_eof = TRUE;
28532654012fSReza Sabdar 		buf->tb_buffer_size = 0;
28542654012fSReza Sabdar 	}
28552654012fSReza Sabdar 
28562654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
28572654012fSReza Sabdar 	    " errno: %d, size: %d, data: 0x%x",
28582654012fSReza Sabdar 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
28592654012fSReza Sabdar 	    buf->tb_buffer_size, buf->tb_buffer_data);
28602654012fSReza Sabdar 
28612654012fSReza Sabdar 	return (0);
28622654012fSReza Sabdar }
28632654012fSReza Sabdar 
28642654012fSReza Sabdar 
28652654012fSReza Sabdar 
28662654012fSReza Sabdar /*
28672654012fSReza Sabdar  * mover_socket_reader
28682654012fSReza Sabdar  *
28692654012fSReza Sabdar  * Mover socket reader thread. This is used when reading data from the
28702654012fSReza Sabdar  * network socket for performing remote backups.
28712654012fSReza Sabdar  *
28722654012fSReza Sabdar  * Parameters:
28732654012fSReza Sabdar  *   session (input) - session pointer.
28742654012fSReza Sabdar  *
28752654012fSReza Sabdar  * Returns:
28762654012fSReza Sabdar  *   0: on success
28772654012fSReza Sabdar  *  -1: otherwise
28782654012fSReza Sabdar  */
2879*82049ff5SToomas Soome void *
mover_socket_reader(void * ptr)2880*82049ff5SToomas Soome mover_socket_reader(void *ptr)
28812654012fSReza Sabdar {
28822654012fSReza Sabdar 	int bidx;	/* buffer index */
28832654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
28842654012fSReza Sabdar 	tlm_buffer_t *buf;
28852654012fSReza Sabdar 	tlm_buffers_t *bufs;
28862654012fSReza Sabdar 	tlm_cmd_t *lcmd;	/* Local command */
28872654012fSReza Sabdar 	tlm_commands_t *cmds;	/* Commands structure */
2888*82049ff5SToomas Soome 	ndmpd_session_t *session = ptr;
28892654012fSReza Sabdar 	static int nr = 0;
28902654012fSReza Sabdar 
28912654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
28922654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2893*82049ff5SToomas Soome 		return ((void *)(uintptr_t)-1);
28942654012fSReza Sabdar 	}
28952654012fSReza Sabdar 
28962654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
28972654012fSReza Sabdar 	lcmd = cmds->tcs_command;
28982654012fSReza Sabdar 	bufs = lcmd->tc_buffers;
28992654012fSReza Sabdar 
29002654012fSReza Sabdar 	lcmd->tc_ref++;
29012654012fSReza Sabdar 	cmds->tcs_reader_count++;
29022654012fSReza Sabdar 
29032654012fSReza Sabdar 	/*
29042654012fSReza Sabdar 	 * Let our parent thread know that we are running.
29052654012fSReza Sabdar 	 */
29062654012fSReza Sabdar 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
29072654012fSReza Sabdar 
29082654012fSReza Sabdar 	bidx = bufs->tbs_buffer_in;
29092654012fSReza Sabdar 	while (cmds->tcs_reader == TLM_BACKUP_RUN &&
29102654012fSReza Sabdar 	    lcmd->tc_reader == TLM_BACKUP_RUN) {
29112654012fSReza Sabdar 		buf = &bufs->tbs_buffer[bidx];
29122654012fSReza Sabdar 
29132654012fSReza Sabdar 		if (buf->tb_full) {
29142654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
29152654012fSReza Sabdar 			/*
29162654012fSReza Sabdar 			 * The buffer is still full, wait for the consumer
29172654012fSReza Sabdar 			 * thread to use it.
29182654012fSReza Sabdar 			 */
29192654012fSReza Sabdar 			tlm_buffer_out_buf_timed_wait(bufs, 100);
29202654012fSReza Sabdar 		} else {
29212654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
29222654012fSReza Sabdar 
29232654012fSReza Sabdar 			(void) mover_socket_read_one_buf(session, buf,
29242654012fSReza Sabdar 			    bufs->tbs_data_transfer_size);
29252654012fSReza Sabdar 
29262654012fSReza Sabdar 			/*
29272654012fSReza Sabdar 			 * Can we do more buffering?
29282654012fSReza Sabdar 			 */
29292654012fSReza Sabdar 			if (is_buffer_erroneous(buf)) {
29302654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
29312654012fSReza Sabdar 				    "Exiting, errno: %d, eot: %d, eof: %d",
29322654012fSReza Sabdar 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
29332654012fSReza Sabdar 				break;
29342654012fSReza Sabdar 			}
29352654012fSReza Sabdar 
29362654012fSReza Sabdar 			(void) tlm_buffer_advance_in_idx(bufs);
29372654012fSReza Sabdar 			tlm_buffer_release_in_buf(bufs);
29382654012fSReza Sabdar 			bidx = bufs->tbs_buffer_in;
29392654012fSReza Sabdar 		}
29402654012fSReza Sabdar 	}
29412654012fSReza Sabdar 
29422654012fSReza Sabdar 	if (cmds->tcs_reader != TLM_BACKUP_RUN)
29432654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
29442654012fSReza Sabdar 	if (lcmd->tc_reader != TLM_BACKUP_RUN)
29452654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
29462654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
29472654012fSReza Sabdar 
29482654012fSReza Sabdar 	/* If the consumer is waiting for us, wake it up. */
29492654012fSReza Sabdar 	tlm_buffer_release_in_buf(bufs);
29502654012fSReza Sabdar 
29512654012fSReza Sabdar 	/*
29522654012fSReza Sabdar 	 * Clean up.
29532654012fSReza Sabdar 	 */
29542654012fSReza Sabdar 	cmds->tcs_reader_count--;
29552654012fSReza Sabdar 	lcmd->tc_ref--;
29562654012fSReza Sabdar 	lcmd->tc_writer = TLM_STOP;
2957*82049ff5SToomas Soome 	return (NULL);
29582654012fSReza Sabdar }
29592654012fSReza Sabdar 
29602654012fSReza Sabdar 
29612654012fSReza Sabdar /*
29622654012fSReza Sabdar  * mover_tape_writer_one_buf
29632654012fSReza Sabdar  *
29642654012fSReza Sabdar  * Write one buffer for the mover to the local tape device. This is
29652654012fSReza Sabdar  * used by mover_tape_writer thread.
29662654012fSReza Sabdar  *
29672654012fSReza Sabdar  * Parameters:
29682654012fSReza Sabdar  *   session (input) - session pointer.
29692654012fSReza Sabdar  *   buf (input) - buffer read
29702654012fSReza Sabdar  *
29712654012fSReza Sabdar  * Returns:
29722654012fSReza Sabdar  *   0: on success
29732654012fSReza Sabdar  *  -1: otherwise
29742654012fSReza Sabdar  */
29752654012fSReza Sabdar static int
mover_tape_write_one_buf(ndmpd_session_t * session,tlm_buffer_t * buf)29762654012fSReza Sabdar mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
29772654012fSReza Sabdar {
29782654012fSReza Sabdar 	int n;
29792654012fSReza Sabdar 
29802654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
29812654012fSReza Sabdar 	    " errno: %d, size: %d, data: 0x%x",
29822654012fSReza Sabdar 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
29832654012fSReza Sabdar 	    buf->tb_buffer_size, buf->tb_buffer_data);
29842654012fSReza Sabdar 
29859ee94b97SJan Kryl 	n = mover_tape_write_v3(session, buf->tb_buffer_data,
29869ee94b97SJan Kryl 	    buf->tb_buffer_size);
29872654012fSReza Sabdar 
29882654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "n: %d", n);
29892654012fSReza Sabdar 
29902654012fSReza Sabdar 	if (n <= 0) {
29912654012fSReza Sabdar 		ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
29922654012fSReza Sabdar 		    : NDMP_MOVER_HALT_INTERNAL_ERROR));
29932654012fSReza Sabdar 		return (-1);
29942654012fSReza Sabdar 	}
29952654012fSReza Sabdar 	session->ns_mover.md_position += n;
29962654012fSReza Sabdar 	session->ns_mover.md_data_written += n;
29972654012fSReza Sabdar 	session->ns_mover.md_record_num++;
29982654012fSReza Sabdar 
29992654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
30002654012fSReza Sabdar 	tlm_buffer_mark_empty(buf);
30012654012fSReza Sabdar 
30022654012fSReza Sabdar 	return (0);
30032654012fSReza Sabdar }
30042654012fSReza Sabdar 
30052654012fSReza Sabdar 
30062654012fSReza Sabdar /*
30072654012fSReza Sabdar  * mover_tape_writer
30082654012fSReza Sabdar  *
30092654012fSReza Sabdar  * Mover tape writer thread. This is used for performing remote backups
30102654012fSReza Sabdar  * in a 3-way configuration. It writes the data from network socket to
30112654012fSReza Sabdar  * the locally attached tape device.
30122654012fSReza Sabdar  *
30132654012fSReza Sabdar  * Parameters:
30142654012fSReza Sabdar  *   session (input) - session pointer.
30152654012fSReza Sabdar  *
30162654012fSReza Sabdar  * Returns:
30172654012fSReza Sabdar  *   0: on success
30182654012fSReza Sabdar  *  -1: otherwise
30192654012fSReza Sabdar  */
3020*82049ff5SToomas Soome void *
mover_tape_writer(void * ptr)3021*82049ff5SToomas Soome mover_tape_writer(void *ptr)
30222654012fSReza Sabdar {
30232654012fSReza Sabdar 	int bidx;
30242654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
30252654012fSReza Sabdar 	tlm_buffer_t *buf;
30262654012fSReza Sabdar 	tlm_buffers_t *bufs;
30272654012fSReza Sabdar 	tlm_cmd_t *lcmd;
30282654012fSReza Sabdar 	tlm_commands_t *cmds;
3029*82049ff5SToomas Soome 	ndmpd_session_t *session = ptr;
30302654012fSReza Sabdar 	static int nw = 0;
30312654012fSReza Sabdar 
30322654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
30332654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3034*82049ff5SToomas Soome 		return ((void *)(uintptr_t)-1);
30352654012fSReza Sabdar 	}
30362654012fSReza Sabdar 
30372654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
30382654012fSReza Sabdar 	lcmd = cmds->tcs_command;
30392654012fSReza Sabdar 	bufs = lcmd->tc_buffers;
30402654012fSReza Sabdar 
30412654012fSReza Sabdar 	lcmd->tc_ref++;
30422654012fSReza Sabdar 	cmds->tcs_writer_count++;
30432654012fSReza Sabdar 
30442654012fSReza Sabdar 	/*
30452654012fSReza Sabdar 	 * Let our parent thread know that we are running.
30462654012fSReza Sabdar 	 */
30472654012fSReza Sabdar 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
30482654012fSReza Sabdar 
30492654012fSReza Sabdar 	bidx = bufs->tbs_buffer_out;
30502654012fSReza Sabdar 	buf = &bufs->tbs_buffer[bidx];
30512654012fSReza Sabdar 	while (cmds->tcs_writer != (int)TLM_ABORT &&
30522654012fSReza Sabdar 	    lcmd->tc_writer != (int)TLM_ABORT) {
30532654012fSReza Sabdar 		if (buf->tb_full) {
30542654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
30552654012fSReza Sabdar 
30562654012fSReza Sabdar 			if (mover_tape_write_one_buf(session, buf) < 0) {
30572654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
30582654012fSReza Sabdar 				    "mover_tape_write_one_buf() failed");
30592654012fSReza Sabdar 				break;
30602654012fSReza Sabdar 			}
30612654012fSReza Sabdar 
30622654012fSReza Sabdar 			(void) tlm_buffer_advance_out_idx(bufs);
30632654012fSReza Sabdar 			tlm_buffer_release_out_buf(bufs);
30642654012fSReza Sabdar 			bidx = bufs->tbs_buffer_out;
30652654012fSReza Sabdar 			buf = &bufs->tbs_buffer[bidx];
30662654012fSReza Sabdar 		} else {
30672654012fSReza Sabdar 			if (lcmd->tc_writer != TLM_BACKUP_RUN) {
30682654012fSReza Sabdar 				/* No more data is coming, time to exit */
30692654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Time to exit");
30702654012fSReza Sabdar 				break;
30712654012fSReza Sabdar 			}
30722654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
30732654012fSReza Sabdar 			/*
30742654012fSReza Sabdar 			 * The buffer is not full, wait for the producer
30752654012fSReza Sabdar 			 * thread to fill it.
30762654012fSReza Sabdar 			 */
30772654012fSReza Sabdar 			tlm_buffer_in_buf_timed_wait(bufs, 100);
30782654012fSReza Sabdar 		}
30792654012fSReza Sabdar 	}
30802654012fSReza Sabdar 
30812654012fSReza Sabdar 	if (cmds->tcs_writer == (int)TLM_ABORT)
30822654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
30832654012fSReza Sabdar 	if (lcmd->tc_writer == (int)TLM_ABORT)
30842654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
30852654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
30862654012fSReza Sabdar 
30872654012fSReza Sabdar 	if (buf->tb_errno == 0) {
30882654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
30892654012fSReza Sabdar 	} else {
30902654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
30912654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
30922654012fSReza Sabdar 	}
30932654012fSReza Sabdar 
30942654012fSReza Sabdar 	/* If the producer is waiting for us, wake it up. */
30952654012fSReza Sabdar 	tlm_buffer_release_out_buf(bufs);
30962654012fSReza Sabdar 
30972654012fSReza Sabdar 	/*
30982654012fSReza Sabdar 	 * Clean up.
30992654012fSReza Sabdar 	 */
31002654012fSReza Sabdar 	cmds->tcs_writer_count--;
31012654012fSReza Sabdar 	lcmd->tc_ref--;
31022654012fSReza Sabdar 	lcmd->tc_reader = TLM_STOP;
3103*82049ff5SToomas Soome 	return (NULL);
31042654012fSReza Sabdar }
31052654012fSReza Sabdar 
31062654012fSReza Sabdar 
31072654012fSReza Sabdar /*
31082654012fSReza Sabdar  * start_mover_for_backup
31092654012fSReza Sabdar  *
31102654012fSReza Sabdar  * Starts a remote backup by running socket reader and tape
31112654012fSReza Sabdar  * writer threads. The mover runs a remote backup in a 3-way backup
31122654012fSReza Sabdar  * configuration.
31132654012fSReza Sabdar  *
31142654012fSReza Sabdar  * Parameters:
31152654012fSReza Sabdar  *   session (input) - session pointer.
31162654012fSReza Sabdar  *
31172654012fSReza Sabdar  * Returns:
31182654012fSReza Sabdar  *   0: on success
31192654012fSReza Sabdar  *  -1: otherwise
31202654012fSReza Sabdar  */
31212654012fSReza Sabdar static int
start_mover_for_backup(ndmpd_session_t * session)31222654012fSReza Sabdar start_mover_for_backup(ndmpd_session_t *session)
31232654012fSReza Sabdar {
31242654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
31252654012fSReza Sabdar 	tlm_commands_t *cmds;
31262654012fSReza Sabdar 	int rc;
31272654012fSReza Sabdar 
31282654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
31292654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
31302654012fSReza Sabdar 		return (-1);
31312654012fSReza Sabdar 	}
31322654012fSReza Sabdar 
31332654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
31342654012fSReza Sabdar 	(void) memset(cmds, 0, sizeof (*cmds));
31352654012fSReza Sabdar 	cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
31362654012fSReza Sabdar 	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
31372654012fSReza Sabdar 	    session->ns_mover.md_record_size);
31382654012fSReza Sabdar 	if (cmds->tcs_command == NULL)
31392654012fSReza Sabdar 		return (-1);
31402654012fSReza Sabdar 
31412654012fSReza Sabdar 	cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
31422654012fSReza Sabdar 	cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
31432654012fSReza Sabdar 
31442654012fSReza Sabdar 	/*
31452654012fSReza Sabdar 	 * We intentionally don't wait for the threads to start since the
31462654012fSReza Sabdar 	 * reply of the request (which resulted in calling this function)
31472654012fSReza Sabdar 	 * must be sent to the client before probable errors are sent
31482654012fSReza Sabdar 	 * to the client.
31492654012fSReza Sabdar 	 */
3150*82049ff5SToomas Soome 	rc = pthread_create(NULL, NULL, mover_socket_reader, session);
31512654012fSReza Sabdar 	if (rc == 0) {
31522654012fSReza Sabdar 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
31532654012fSReza Sabdar 	} else {
31542654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
31552654012fSReza Sabdar 		    strerror(rc));
31562654012fSReza Sabdar 		return (-1);
31572654012fSReza Sabdar 	}
31582654012fSReza Sabdar 
3159*82049ff5SToomas Soome 	rc = pthread_create(NULL, NULL, mover_tape_writer, session);
31602654012fSReza Sabdar 	if (rc == 0) {
31612654012fSReza Sabdar 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
31622654012fSReza Sabdar 	} else {
31632654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
31642654012fSReza Sabdar 		    strerror(rc));
31652654012fSReza Sabdar 		return (-1);
31662654012fSReza Sabdar 	}
31672654012fSReza Sabdar 
31682654012fSReza Sabdar 	tlm_release_reader_writer_ipc(cmds->tcs_command);
31692654012fSReza Sabdar 	return (0);
31702654012fSReza Sabdar }
31712654012fSReza Sabdar 
31722654012fSReza Sabdar 
31732654012fSReza Sabdar /*
31742654012fSReza Sabdar  * is_writer_running
31752654012fSReza Sabdar  *
31762654012fSReza Sabdar  * Find out if the writer thread has started or not.
31772654012fSReza Sabdar  *
31782654012fSReza Sabdar  * Parameters:
31792654012fSReza Sabdar  *   session (input) - session pointer.
31802654012fSReza Sabdar  *
31812654012fSReza Sabdar  * Returns:
31822654012fSReza Sabdar  *   0: not started
31832654012fSReza Sabdar  *   non-zero: started
31848c4f9701SJanice Chang  *	Note: non-zero is also returned if the backup type is
31858c4f9701SJanice Chang  *		neither TAR nor DUMP.  I.e. the is_writer_running()
31868c4f9701SJanice Chang  *		check does not apply in this case and things should
3187*82049ff5SToomas Soome  *		appear successful.
31882654012fSReza Sabdar  */
31892654012fSReza Sabdar static boolean_t
is_writer_running(ndmpd_session_t * session)31902654012fSReza Sabdar is_writer_running(ndmpd_session_t *session)
31912654012fSReza Sabdar {
31922654012fSReza Sabdar 	boolean_t rv;
31932654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
31942654012fSReza Sabdar 
31958c4f9701SJanice Chang 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
31968c4f9701SJanice Chang 		return (1);
31978c4f9701SJanice Chang 
31982654012fSReza Sabdar 	if (session == NULL)
31992654012fSReza Sabdar 		rv = 0;
32002654012fSReza Sabdar 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
32012654012fSReza Sabdar 		rv = 0;
32022654012fSReza Sabdar 	else
32032654012fSReza Sabdar 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
32042654012fSReza Sabdar 
32052654012fSReza Sabdar 	return (rv);
32062654012fSReza Sabdar }
32072654012fSReza Sabdar 
32082654012fSReza Sabdar 
32092654012fSReza Sabdar /*
32102654012fSReza Sabdar  * is_writer_running_v3
32112654012fSReza Sabdar  *
32122654012fSReza Sabdar  * Find out if the writer thread has started or not.
32132654012fSReza Sabdar  *
32142654012fSReza Sabdar  * Parameters:
32152654012fSReza Sabdar  *   session (input) - session pointer.
32162654012fSReza Sabdar  *
32172654012fSReza Sabdar  * Returns:
32182654012fSReza Sabdar  *   0: not started
32192654012fSReza Sabdar  *   non-zero: started
32208c4f9701SJanice Chang  *	Note: non-zero is also returned if the backup type is
32218c4f9701SJanice Chang  *		neither TAR nor DUMP.  I.e. the is_writer_running()
32228c4f9701SJanice Chang  *		check does not apply in this case and things should
3223*82049ff5SToomas Soome  *		appear successful.
32242654012fSReza Sabdar  */
32252654012fSReza Sabdar static boolean_t
is_writer_running_v3(ndmpd_session_t * session)32262654012fSReza Sabdar is_writer_running_v3(ndmpd_session_t *session)
32272654012fSReza Sabdar {
32282654012fSReza Sabdar 	boolean_t rv;
32292654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
32302654012fSReza Sabdar 
32318c4f9701SJanice Chang 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
32328c4f9701SJanice Chang 		return (1);
32338c4f9701SJanice Chang 
32342654012fSReza Sabdar 	if (session == NULL)
32352654012fSReza Sabdar 		rv = 0;
32362654012fSReza Sabdar 	else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
32372654012fSReza Sabdar 		rv = 1;
32382654012fSReza Sabdar 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
32392654012fSReza Sabdar 		rv = 0;
32402654012fSReza Sabdar 	else
32412654012fSReza Sabdar 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
32422654012fSReza Sabdar 
32432654012fSReza Sabdar 	return (rv);
32442654012fSReza Sabdar }
32452654012fSReza Sabdar 
32462654012fSReza Sabdar 
32472654012fSReza Sabdar /*
32482654012fSReza Sabdar  * ndmpd_mover_error_send
32492654012fSReza Sabdar  *
32502654012fSReza Sabdar  * This function sends the notify message to the client.
32512654012fSReza Sabdar  *
32522654012fSReza Sabdar  * Parameters:
32532654012fSReza Sabdar  *   session (input) - session pointer.
32542654012fSReza Sabdar  *   reason  (input) - halt reason.
32552654012fSReza Sabdar  *
32562654012fSReza Sabdar  * Returns:
32572654012fSReza Sabdar  *   Error code
32582654012fSReza Sabdar  */
32592654012fSReza Sabdar int
ndmpd_mover_error_send(ndmpd_session_t * session,ndmp_mover_halt_reason reason)32602654012fSReza Sabdar ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
32612654012fSReza Sabdar {
32622654012fSReza Sabdar 	ndmp_notify_mover_halted_request req;
32632654012fSReza Sabdar 
32642654012fSReza Sabdar 	req.reason = reason;
32652654012fSReza Sabdar 	req.text_reason = "";
32662654012fSReza Sabdar 
32672654012fSReza Sabdar 	return (ndmp_send_request(session->ns_connection,
32682654012fSReza Sabdar 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
32692654012fSReza Sabdar }
32702654012fSReza Sabdar 
32712654012fSReza Sabdar 
32722654012fSReza Sabdar /*
32732654012fSReza Sabdar  * ndmpd_mover_error_send_v4
32742654012fSReza Sabdar  *
32752654012fSReza Sabdar  * This function sends the notify message to the client.
32762654012fSReza Sabdar  *
32772654012fSReza Sabdar  * Parameters:
32782654012fSReza Sabdar  *   session (input) - session pointer.
32792654012fSReza Sabdar  *   reason  (input) - halt reason.
32802654012fSReza Sabdar  *
32812654012fSReza Sabdar  * Returns:
32822654012fSReza Sabdar  *   Error code
32832654012fSReza Sabdar  */
32842654012fSReza Sabdar int
ndmpd_mover_error_send_v4(ndmpd_session_t * session,ndmp_mover_halt_reason reason)32852654012fSReza Sabdar ndmpd_mover_error_send_v4(ndmpd_session_t *session,
32862654012fSReza Sabdar     ndmp_mover_halt_reason reason)
32872654012fSReza Sabdar {
32882654012fSReza Sabdar 	ndmp_notify_mover_halted_request_v4 req;
32892654012fSReza Sabdar 
32902654012fSReza Sabdar 	req.reason = reason;
32912654012fSReza Sabdar 
32922654012fSReza Sabdar 	return (ndmp_send_request(session->ns_connection,
32932654012fSReza Sabdar 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
32942654012fSReza Sabdar }
32952654012fSReza Sabdar 
32962654012fSReza Sabdar 
32972654012fSReza Sabdar /*
32982654012fSReza Sabdar  * ndmpd_mover_error
32992654012fSReza Sabdar  *
33002654012fSReza Sabdar  * This function is called when an unrecoverable mover error
33012654012fSReza Sabdar  * has been detected. A notify message is sent to the client and the
33022654012fSReza Sabdar  * mover is placed into the halted state.
33032654012fSReza Sabdar  *
33042654012fSReza Sabdar  * Parameters:
33052654012fSReza Sabdar  *   session (input) - session pointer.
33062654012fSReza Sabdar  *   reason  (input) - halt reason.
33072654012fSReza Sabdar  *
33082654012fSReza Sabdar  * Returns:
33092654012fSReza Sabdar  *   void.
33102654012fSReza Sabdar  */
33112654012fSReza Sabdar void
ndmpd_mover_error(ndmpd_session_t * session,ndmp_mover_halt_reason reason)33122654012fSReza Sabdar ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
33132654012fSReza Sabdar {
3314a23888a3SJan Kryl 	ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
3315a23888a3SJan Kryl 
33162654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
33172654012fSReza Sabdar 	    (session->ns_protocol_version > NDMPV2 &&
33182654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
33192654012fSReza Sabdar 		return;
33202654012fSReza Sabdar 
33212654012fSReza Sabdar 	if (session->ns_protocol_version == NDMPV4) {
33222654012fSReza Sabdar 		if (ndmpd_mover_error_send_v4(session, reason) < 0)
33232654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
33242654012fSReza Sabdar 			    "Error sending notify_mover_halted request");
33252654012fSReza Sabdar 	} else {
33262654012fSReza Sabdar 		/* No media error in V3 */
33272654012fSReza Sabdar 		if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
33282654012fSReza Sabdar 			reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
33292654012fSReza Sabdar 		if (ndmpd_mover_error_send(session, reason) < 0)
33302654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
33312654012fSReza Sabdar 			    "Error sending notify_mover_halted request");
33322654012fSReza Sabdar 	}
33332654012fSReza Sabdar 
3334a23888a3SJan Kryl 	(void) mutex_lock(&nlp->nlp_mtx);
33352654012fSReza Sabdar 	if (session->ns_mover.md_listen_sock != -1) {
33362654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
33372654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
33382654012fSReza Sabdar 		(void) close(session->ns_mover.md_listen_sock);
33392654012fSReza Sabdar 		session->ns_mover.md_listen_sock = -1;
33402654012fSReza Sabdar 	}
33412654012fSReza Sabdar 	if (session->ns_mover.md_sock != -1) {
33422654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
33432654012fSReza Sabdar 		    session->ns_mover.md_sock);
33442654012fSReza Sabdar 		(void) close(session->ns_mover.md_sock);
33452654012fSReza Sabdar 		session->ns_mover.md_sock = -1;
33462654012fSReza Sabdar 	}
33472654012fSReza Sabdar 
33482654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
33492654012fSReza Sabdar 	session->ns_mover.md_halt_reason = reason;
3350a23888a3SJan Kryl 	(void) cond_broadcast(&nlp->nlp_cv);
3351a23888a3SJan Kryl 	(void) mutex_unlock(&nlp->nlp_mtx);
33522654012fSReza Sabdar }
33532654012fSReza Sabdar 
33542654012fSReza Sabdar 
33552654012fSReza Sabdar /*
33562654012fSReza Sabdar  * mover_pause_v3
33572654012fSReza Sabdar  *
33582654012fSReza Sabdar  * Send an ndmp_notify_mover_paused request to the
33592654012fSReza Sabdar  * NDMP client to inform the client that its attention is required.
33602654012fSReza Sabdar  * Process messages until the data/mover operation is either aborted
33612654012fSReza Sabdar  * or continued.
33622654012fSReza Sabdar  *
33632654012fSReza Sabdar  * Parameters:
33642654012fSReza Sabdar  *   client_data (input) - session pointer.
33652654012fSReza Sabdar  *   reason (input) - pause reason.
33662654012fSReza Sabdar  *
33672654012fSReza Sabdar  * Returns:
33682654012fSReza Sabdar  *   0 - operation has been continued.
33692654012fSReza Sabdar  *  -1 - operation has been aborted.
33702654012fSReza Sabdar  */
33712654012fSReza Sabdar static int
mover_pause_v3(ndmpd_session_t * session,ndmp_mover_pause_reason reason)33722654012fSReza Sabdar mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
33732654012fSReza Sabdar {
33742654012fSReza Sabdar 	int rv;
33752654012fSReza Sabdar 	ndmp_notify_mover_paused_request request;
33762654012fSReza Sabdar 
33772654012fSReza Sabdar 	rv = 0;
33782654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
33792654012fSReza Sabdar 	session->ns_mover.md_pause_reason = reason;
33802654012fSReza Sabdar 	session->ns_mover.md_pre_cond = FALSE;
33812654012fSReza Sabdar 
33822654012fSReza Sabdar 	request.reason = session->ns_mover.md_pause_reason;
33832654012fSReza Sabdar 	request.seek_position =
33842654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_position);
33852654012fSReza Sabdar 
33862654012fSReza Sabdar 	if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
33872654012fSReza Sabdar 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
33882654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
33892654012fSReza Sabdar 		    "Error sending notify_mover_paused_request");
33902654012fSReza Sabdar 		return (-1);
33912654012fSReza Sabdar 	}
33922654012fSReza Sabdar 
33932654012fSReza Sabdar 	/*
33942654012fSReza Sabdar 	 * 3-way operations are single-thread.  The same thread
33952654012fSReza Sabdar 	 * should process the messages.
33962654012fSReza Sabdar 	 *
33972654012fSReza Sabdar 	 * 2-way operations are multi-thread.  The main thread
33982654012fSReza Sabdar 	 * processes the messages.  We just need to wait and
33992654012fSReza Sabdar 	 * see if the mover state changes or the operation aborts.
34002654012fSReza Sabdar 	 */
34012654012fSReza Sabdar 	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
34022654012fSReza Sabdar 		/*
34032654012fSReza Sabdar 		 * Process messages until the state is changed by
34042654012fSReza Sabdar 		 * an abort, continue, or close request .
34052654012fSReza Sabdar 		 */
34062654012fSReza Sabdar 		for (; ; ) {
34072654012fSReza Sabdar 			if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
34082654012fSReza Sabdar 				return (-1);
34092654012fSReza Sabdar 
34102654012fSReza Sabdar 			if (session->ns_eof == TRUE)
34112654012fSReza Sabdar 				return (-1);
34122654012fSReza Sabdar 
34132654012fSReza Sabdar 			switch (session->ns_mover.md_state) {
34142654012fSReza Sabdar 			case NDMP_MOVER_STATE_ACTIVE:
34152654012fSReza Sabdar 				session->ns_tape.td_record_count = 0;
34162654012fSReza Sabdar 				return (0);
34172654012fSReza Sabdar 
34182654012fSReza Sabdar 			case NDMP_MOVER_STATE_PAUSED:
34192654012fSReza Sabdar 				continue;
34202654012fSReza Sabdar 
34212654012fSReza Sabdar 			default:
34222654012fSReza Sabdar 				return (-1);
34232654012fSReza Sabdar 			}
34242654012fSReza Sabdar 		}
34252654012fSReza Sabdar 
34262654012fSReza Sabdar 	} else {
34272654012fSReza Sabdar 		if (session->ns_mover.md_data_addr.addr_type ==
34282654012fSReza Sabdar 		    NDMP_ADDR_LOCAL) {
3429a23888a3SJan Kryl 			rv = ndmp_wait_for_mover(session);
34302654012fSReza Sabdar 		} else {
34312654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
34322654012fSReza Sabdar 			    session->ns_mover.md_data_addr.addr_type);
34332654012fSReza Sabdar 			rv = -1;
34342654012fSReza Sabdar 		}
34352654012fSReza Sabdar 	}
34362654012fSReza Sabdar 
34372654012fSReza Sabdar 	return (rv);
34382654012fSReza Sabdar }
34392654012fSReza Sabdar 
34402654012fSReza Sabdar 
34412654012fSReza Sabdar /*
34422654012fSReza Sabdar  * mover_tape_write_v3
34432654012fSReza Sabdar  *
34442654012fSReza Sabdar  * Writes a data record to tape. Detects and handles EOT conditions.
34452654012fSReza Sabdar  *
34462654012fSReza Sabdar  * Parameters:
34472654012fSReza Sabdar  *   session (input) - session pointer.
34482654012fSReza Sabdar  *   data    (input) - data to be written.
34492654012fSReza Sabdar  *   length  (input) - length of data to be written.
34502654012fSReza Sabdar  *
34512654012fSReza Sabdar  * Returns:
34522654012fSReza Sabdar  *    0 - operation aborted by client.
34532654012fSReza Sabdar  *   -1 - error.
34542654012fSReza Sabdar  *   otherwise - number of bytes written.
34552654012fSReza Sabdar  */
34562654012fSReza Sabdar static int
mover_tape_write_v3(ndmpd_session_t * session,char * data,ssize_t length)34572654012fSReza Sabdar mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
34582654012fSReza Sabdar {
34592654012fSReza Sabdar 	ssize_t n;
34609ee94b97SJan Kryl 	ssize_t count = length;
34612654012fSReza Sabdar 
34629ee94b97SJan Kryl 	while (count > 0) {
34632654012fSReza Sabdar 		/*
34642654012fSReza Sabdar 		 * Enforce mover window on write.
34652654012fSReza Sabdar 		 */
34662654012fSReza Sabdar 		if (session->ns_mover.md_position >=
34672654012fSReza Sabdar 		    session->ns_mover.md_window_offset +
34682654012fSReza Sabdar 		    session->ns_mover.md_window_length) {
34692654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
34702654012fSReza Sabdar 
34719ee94b97SJan Kryl 			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW) < 0)
34729ee94b97SJan Kryl 				/* Operation aborted or connection terminated */
34732654012fSReza Sabdar 				return (-1);
34742654012fSReza Sabdar 
34752654012fSReza Sabdar 		}
34762654012fSReza Sabdar 
34779ee94b97SJan Kryl 		n = write(session->ns_tape.td_fd, data, count);
34782654012fSReza Sabdar 		if (n < 0) {
34792654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
34802654012fSReza Sabdar 			return (-1);
34819ee94b97SJan Kryl 		} else if (n > 0) {
34829ee94b97SJan Kryl 			NS_ADD(wtape, n);
34839ee94b97SJan Kryl 			count -= n;
34849ee94b97SJan Kryl 			data += n;
34859ee94b97SJan Kryl 			session->ns_tape.td_record_count++;
34862654012fSReza Sabdar 		}
34872654012fSReza Sabdar 
34889ee94b97SJan Kryl 		/* EOM handling */
34899ee94b97SJan Kryl 		if (count > 0) {
34909ee94b97SJan Kryl 			struct mtget mtstatus;
34912654012fSReza Sabdar 
34929ee94b97SJan Kryl 			(void) ioctl(session->ns_tape.td_fd, MTIOCGET,
34939ee94b97SJan Kryl 			    &mtstatus);
34949ee94b97SJan Kryl 			NDMP_LOG(LOG_DEBUG, "EOM detected (%d written bytes, "
34959ee94b97SJan Kryl 			    "mover record %d, file #%d, block #%d)", n,
34969ee94b97SJan Kryl 			    session->ns_tape.td_record_count,
34979ee94b97SJan Kryl 			    mtstatus.mt_fileno, mtstatus.mt_blkno);
34982654012fSReza Sabdar 
34992654012fSReza Sabdar 			/*
35009ee94b97SJan Kryl 			 * Notify the client to either abort the operation
35019ee94b97SJan Kryl 			 * or change the tape.
35022654012fSReza Sabdar 			 */
35032654012fSReza Sabdar 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
35042654012fSReza Sabdar 			    ++ndmp_log_msg_id,
35052654012fSReza Sabdar 			    "End of tape reached. Load next tape");
35062654012fSReza Sabdar 
35079ee94b97SJan Kryl 			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM) < 0)
35089ee94b97SJan Kryl 				/* Operation aborted or connection terminated */
35092654012fSReza Sabdar 				return (-1);
35102654012fSReza Sabdar 		}
35112654012fSReza Sabdar 	}
35129ee94b97SJan Kryl 
35139ee94b97SJan Kryl 	return (length);
35142654012fSReza Sabdar }
35152654012fSReza Sabdar 
35162654012fSReza Sabdar 
35172654012fSReza Sabdar /*
35182654012fSReza Sabdar  * mover_tape_flush_v3
35192654012fSReza Sabdar  *
35202654012fSReza Sabdar  * Writes all remaining buffered data to tape. A partial record is
35212654012fSReza Sabdar  * padded out to a full record with zeros.
35222654012fSReza Sabdar  *
35232654012fSReza Sabdar  * Parameters:
35242654012fSReza Sabdar  *   session (input) - session pointer.
35252654012fSReza Sabdar  *   data    (input) - data to be written.
35262654012fSReza Sabdar  *   length  (input) - length of data to be written.
35272654012fSReza Sabdar  *
35282654012fSReza Sabdar  * Returns:
35292654012fSReza Sabdar  *   -1 - error.
35302654012fSReza Sabdar  *   otherwise - number of bytes written.
35312654012fSReza Sabdar  */
35322654012fSReza Sabdar static int
mover_tape_flush_v3(ndmpd_session_t * session)35332654012fSReza Sabdar mover_tape_flush_v3(ndmpd_session_t *session)
35342654012fSReza Sabdar {
35352654012fSReza Sabdar 	int n;
35362654012fSReza Sabdar 
35372654012fSReza Sabdar 	if (session->ns_mover.md_w_index == 0)
35382654012fSReza Sabdar 		return (0);
35392654012fSReza Sabdar 
35402654012fSReza Sabdar 	(void) memset((void*)&session->ns_mover.md_buf[session->
35412654012fSReza Sabdar 	    ns_mover.md_w_index], 0,
35422654012fSReza Sabdar 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
35432654012fSReza Sabdar 
35442654012fSReza Sabdar 	n = mover_tape_write_v3(session, session->ns_mover.md_buf,
35452654012fSReza Sabdar 	    session->ns_mover.md_record_size);
35462654012fSReza Sabdar 	if (n < 0) {
35472654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
35482654012fSReza Sabdar 		return (-1);
35492654012fSReza Sabdar 	}
35502654012fSReza Sabdar 
35512654012fSReza Sabdar 	session->ns_mover.md_w_index = 0;
35522654012fSReza Sabdar 	session->ns_mover.md_position += n;
35532654012fSReza Sabdar 	return (n);
35542654012fSReza Sabdar }
35552654012fSReza Sabdar 
35562654012fSReza Sabdar 
35572654012fSReza Sabdar /*
35582654012fSReza Sabdar  * ndmpd_local_write_v3
35592654012fSReza Sabdar  *
35602654012fSReza Sabdar  * Buffers and writes data to the tape device.
35612654012fSReza Sabdar  * A full tape record is buffered before being written.
35622654012fSReza Sabdar  *
35632654012fSReza Sabdar  * Parameters:
35642654012fSReza Sabdar  *   session    (input) - session pointer.
35652654012fSReza Sabdar  *   data       (input) - data to be written.
35662654012fSReza Sabdar  *   length     (input) - data length.
35672654012fSReza Sabdar  *
35682654012fSReza Sabdar  * Returns:
35692654012fSReza Sabdar  *   0 - data successfully written.
35702654012fSReza Sabdar  *  -1 - error.
35712654012fSReza Sabdar  */
35722654012fSReza Sabdar int
ndmpd_local_write_v3(ndmpd_session_t * session,char * data,ulong_t length)35732654012fSReza Sabdar ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
35742654012fSReza Sabdar {
35752654012fSReza Sabdar 	ulong_t count = 0;
35762654012fSReza Sabdar 	ssize_t n;
35772654012fSReza Sabdar 	ulong_t len;
35782654012fSReza Sabdar 
35792654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
35802654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
35812654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
35822654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
35832654012fSReza Sabdar 		return (-1);
35842654012fSReza Sabdar 	}
35852654012fSReza Sabdar 
35862654012fSReza Sabdar 	/*
35872654012fSReza Sabdar 	 * A length of 0 indicates that any buffered data should be
35882654012fSReza Sabdar 	 * flushed to tape.
35892654012fSReza Sabdar 	 */
35902654012fSReza Sabdar 	if (length == 0) {
35912654012fSReza Sabdar 		if (session->ns_mover.md_w_index == 0)
35922654012fSReza Sabdar 			return (0);
35932654012fSReza Sabdar 
35942654012fSReza Sabdar 		(void) memset((void*)&session->ns_mover.md_buf[session->
35952654012fSReza Sabdar 		    ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
35962654012fSReza Sabdar 		    session->ns_mover.md_w_index);
35972654012fSReza Sabdar 
35982654012fSReza Sabdar 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
35992654012fSReza Sabdar 		    session->ns_mover.md_record_size);
36002654012fSReza Sabdar 		if (n <= 0) {
36012654012fSReza Sabdar 			ndmpd_mover_error(session,
36022654012fSReza Sabdar 			    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
36032654012fSReza Sabdar 			    NDMP_MOVER_HALT_MEDIA_ERROR));
36042654012fSReza Sabdar 			return (-1);
36052654012fSReza Sabdar 		}
36062654012fSReza Sabdar 
36072654012fSReza Sabdar 		session->ns_mover.md_position += n;
36088a5de3ffSReza Sabdar 		session->ns_mover.md_data_written +=
36098a5de3ffSReza Sabdar 		    session->ns_mover.md_w_index;
36102654012fSReza Sabdar 		session->ns_mover.md_record_num++;
36112654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
36122654012fSReza Sabdar 		return (0);
36132654012fSReza Sabdar 	}
36142654012fSReza Sabdar 
36152654012fSReza Sabdar 	/* Break the data into records. */
36162654012fSReza Sabdar 	while (count < length) {
36172654012fSReza Sabdar 		/*
36182654012fSReza Sabdar 		 * Determine if data needs to be buffered or
36192654012fSReza Sabdar 		 * can be written directly from user supplied location.
36202654012fSReza Sabdar 		 * We can fast path the write if there is no pending
36212654012fSReza Sabdar 		 * buffered data and there is at least a full records worth
36222654012fSReza Sabdar 		 * of data to be written.
36232654012fSReza Sabdar 		 */
36242654012fSReza Sabdar 		if (session->ns_mover.md_w_index == 0 &&
36252654012fSReza Sabdar 		    length - count >= session->ns_mover.md_record_size) {
36262654012fSReza Sabdar 			n = mover_tape_write_v3(session, &data[count],
36272654012fSReza Sabdar 			    session->ns_mover.md_record_size);
36282654012fSReza Sabdar 			if (n <= 0) {
36292654012fSReza Sabdar 				ndmpd_mover_error(session,
36302654012fSReza Sabdar 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
36312654012fSReza Sabdar 				    NDMP_MOVER_HALT_MEDIA_ERROR));
36322654012fSReza Sabdar 				return (-1);
36332654012fSReza Sabdar 			}
36342654012fSReza Sabdar 
36352654012fSReza Sabdar 			session->ns_mover.md_position += n;
36362654012fSReza Sabdar 			session->ns_mover.md_data_written += n;
36372654012fSReza Sabdar 			session->ns_mover.md_record_num++;
36382654012fSReza Sabdar 			count += n;
36392654012fSReza Sabdar 			continue;
36402654012fSReza Sabdar 		}
36412654012fSReza Sabdar 
36422654012fSReza Sabdar 		/* Buffer the data */
36432654012fSReza Sabdar 		len = length - count;
36442654012fSReza Sabdar 		if (len > session->ns_mover.md_record_size -
36452654012fSReza Sabdar 		    session->ns_mover.md_w_index)
36462654012fSReza Sabdar 			len = session->ns_mover.md_record_size -
36472654012fSReza Sabdar 			    session->ns_mover.md_w_index;
36482654012fSReza Sabdar 
36492654012fSReza Sabdar 		(void) memcpy(&session->ns_mover.md_buf[session->
36502654012fSReza Sabdar 		    ns_mover.md_w_index], &data[count], len);
36512654012fSReza Sabdar 		session->ns_mover.md_w_index += len;
36522654012fSReza Sabdar 		count += len;
36532654012fSReza Sabdar 
36542654012fSReza Sabdar 		/* Write the buffer if its full */
36552654012fSReza Sabdar 		if (session->ns_mover.md_w_index ==
36562654012fSReza Sabdar 		    session->ns_mover.md_record_size) {
36572654012fSReza Sabdar 			n = mover_tape_write_v3(session,
36582654012fSReza Sabdar 			    session->ns_mover.md_buf,
36592654012fSReza Sabdar 			    session->ns_mover.md_record_size);
36609ee94b97SJan Kryl 			if (n <= 0) {
36612654012fSReza Sabdar 				ndmpd_mover_error(session,
36622654012fSReza Sabdar 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
36632654012fSReza Sabdar 				    NDMP_MOVER_HALT_MEDIA_ERROR));
36642654012fSReza Sabdar 				return (-1);
36652654012fSReza Sabdar 			}
36662654012fSReza Sabdar 
36672654012fSReza Sabdar 			session->ns_mover.md_position += n;
36682654012fSReza Sabdar 			session->ns_mover.md_data_written += n;
36692654012fSReza Sabdar 			session->ns_mover.md_record_num++;
36702654012fSReza Sabdar 			session->ns_mover.md_w_index = 0;
36712654012fSReza Sabdar 		}
36722654012fSReza Sabdar 	}
36732654012fSReza Sabdar 
36742654012fSReza Sabdar 	return (0);
36752654012fSReza Sabdar }
36762654012fSReza Sabdar 
36772654012fSReza Sabdar 
36782654012fSReza Sabdar /*
36792654012fSReza Sabdar  * mover_data_read_v3
36802654012fSReza Sabdar  *
36812654012fSReza Sabdar  * Reads backup data from the data connection and writes the
36822654012fSReza Sabdar  * received data to the tape device.
36832654012fSReza Sabdar  *
36842654012fSReza Sabdar  * Parameters:
36852654012fSReza Sabdar  *   cookie  (input) - session pointer.
36862654012fSReza Sabdar  *   fd      (input) - file descriptor.
36872654012fSReza Sabdar  *   mode    (input) - select mode.
36882654012fSReza Sabdar  *
36892654012fSReza Sabdar  * Returns:
36902654012fSReza Sabdar  *   void.
36912654012fSReza Sabdar  */
36922654012fSReza Sabdar /*ARGSUSED*/
36932654012fSReza Sabdar static void
mover_data_read_v3(void * cookie,int fd,ulong_t mode)36942654012fSReza Sabdar mover_data_read_v3(void *cookie, int fd, ulong_t mode)
36952654012fSReza Sabdar {
36962654012fSReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
36972654012fSReza Sabdar 	int n;
36982654012fSReza Sabdar 	ulong_t index;
36992654012fSReza Sabdar 
37002654012fSReza Sabdar 	n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
37012654012fSReza Sabdar 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
37022654012fSReza Sabdar 
37032654012fSReza Sabdar 	/*
37042654012fSReza Sabdar 	 * Since this function is only called when select believes data
37052654012fSReza Sabdar 	 * is available to be read, a return of zero indicates the
37062654012fSReza Sabdar 	 * connection has been closed.
37072654012fSReza Sabdar 	 */
37082654012fSReza Sabdar 	if (n <= 0) {
370997f7c475SJan Kryl 		if (n == 0) {
371097f7c475SJan Kryl 			NDMP_LOG(LOG_DEBUG, "Data connection closed");
371197f7c475SJan Kryl 			ndmpd_mover_error(session,
371297f7c475SJan Kryl 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
371397f7c475SJan Kryl 		} else {
371497f7c475SJan Kryl 			/* Socket is non-blocking, perhaps there are no data */
371597f7c475SJan Kryl 			if (errno == EAGAIN) {
371697f7c475SJan Kryl 				NDMP_LOG(LOG_ERR, "No data to read");
371797f7c475SJan Kryl 				return;
371897f7c475SJan Kryl 			}
371997f7c475SJan Kryl 
372097f7c475SJan Kryl 			NDMP_LOG(LOG_ERR, "Failed to read from socket: %m");
372197f7c475SJan Kryl 			ndmpd_mover_error(session,
372297f7c475SJan Kryl 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
37232654012fSReza Sabdar 		}
37242654012fSReza Sabdar 
37252654012fSReza Sabdar 		/* Save the index since mover_tape_flush_v3 resets it. */
37262654012fSReza Sabdar 		index = session->ns_mover.md_w_index;
37272654012fSReza Sabdar 
37282654012fSReza Sabdar 		/* Flush any buffered data to tape. */
37292654012fSReza Sabdar 		if (mover_tape_flush_v3(session) > 0) {
37302654012fSReza Sabdar 			session->ns_mover.md_data_written += index;
37312654012fSReza Sabdar 			session->ns_mover.md_record_num++;
37322654012fSReza Sabdar 		}
37332654012fSReza Sabdar 
37342654012fSReza Sabdar 		return;
37352654012fSReza Sabdar 	}
37362654012fSReza Sabdar 
37372654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "n %d", n);
37382654012fSReza Sabdar 
37392654012fSReza Sabdar 	session->ns_mover.md_w_index += n;
37402654012fSReza Sabdar 
37412654012fSReza Sabdar 	if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
37422654012fSReza Sabdar 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
37432654012fSReza Sabdar 		    session->ns_mover.md_record_size);
37442654012fSReza Sabdar 		if (n <= 0) {
37452654012fSReza Sabdar 			ndmpd_mover_error(session,
37462654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
37472654012fSReza Sabdar 			    NDMP_MOVER_HALT_MEDIA_ERROR));
37482654012fSReza Sabdar 			return;
37492654012fSReza Sabdar 		}
37502654012fSReza Sabdar 
37512654012fSReza Sabdar 		session->ns_mover.md_position += n;
37522654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
37532654012fSReza Sabdar 		session->ns_mover.md_data_written += n;
37542654012fSReza Sabdar 		session->ns_mover.md_record_num++;
37552654012fSReza Sabdar 	}
37562654012fSReza Sabdar }
37572654012fSReza Sabdar 
37582654012fSReza Sabdar /*
37592654012fSReza Sabdar  * mover_tape_read_v3
37602654012fSReza Sabdar  *
37612654012fSReza Sabdar  * Reads a data record from tape. Detects and handles EOT conditions.
37622654012fSReza Sabdar  *
37632654012fSReza Sabdar  * Parameters:
37642654012fSReza Sabdar  *   session (input) - session pointer.
37652654012fSReza Sabdar  *   data    (input) - location to read data to.
37662654012fSReza Sabdar  *
37672654012fSReza Sabdar  * Returns:
37682654012fSReza Sabdar  *   0 - operation aborted.
37692654012fSReza Sabdar  *   TAPE_READ_ERR - tape read IO error.
37702654012fSReza Sabdar  *   TAPE_NO_WRITER_ERR - no writer is running during tape read
37712654012fSReza Sabdar  *   otherwise - number of bytes read.
37722654012fSReza Sabdar  */
37732654012fSReza Sabdar static int
mover_tape_read_v3(ndmpd_session_t * session,char * data)37742654012fSReza Sabdar mover_tape_read_v3(ndmpd_session_t *session, char *data)
37752654012fSReza Sabdar {
37769ee94b97SJan Kryl 	int pause_reason;
37772654012fSReza Sabdar 	ssize_t	 n;
37782654012fSReza Sabdar 	int err;
37792654012fSReza Sabdar 	int count;
37802654012fSReza Sabdar 
37812654012fSReza Sabdar 	count = session->ns_mover.md_record_size;
37829ee94b97SJan Kryl 	while (count > 0) {
37839ee94b97SJan Kryl 		pause_reason = NDMP_MOVER_PAUSE_NA;
37849ee94b97SJan Kryl 
37852654012fSReza Sabdar 		n = read(session->ns_tape.td_fd, data, count);
37862654012fSReza Sabdar 		if (n < 0) {
37879ee94b97SJan Kryl 			/*
37889ee94b97SJan Kryl 			 * If at beginning of file and read fails with EIO,
37899ee94b97SJan Kryl 			 * then it's repeated attempt to read at EOT.
37909ee94b97SJan Kryl 			 */
37919ee94b97SJan Kryl 			if (errno == EIO && tape_is_at_bof(session)) {
37929ee94b97SJan Kryl 				NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
37939ee94b97SJan Kryl 				pause_reason = NDMP_MOVER_PAUSE_EOM;
37949ee94b97SJan Kryl 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
37959ee94b97SJan Kryl 				    ++ndmp_log_msg_id,
37969ee94b97SJan Kryl 				    "End of tape reached. Load next tape");
37979ee94b97SJan Kryl 			}
37989ee94b97SJan Kryl 			/*
37999ee94b97SJan Kryl 			 * According to NDMPv4 spec preferred error code when
38009ee94b97SJan Kryl 			 * trying to read from blank tape is NDMP_EOM_ERR.
38019ee94b97SJan Kryl 			 */
38029ee94b97SJan Kryl 			else if (errno == EIO && tape_is_at_bot(session)) {
38039ee94b97SJan Kryl 				NDMP_LOG(LOG_ERR,
38049ee94b97SJan Kryl 				    "Blank tape detected, returning EOM");
38059ee94b97SJan Kryl 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
38069ee94b97SJan Kryl 				    ++ndmp_log_msg_id,
38079ee94b97SJan Kryl 				    "Blank tape. Load another tape");
38089ee94b97SJan Kryl 				pause_reason = NDMP_MOVER_PAUSE_EOM;
38099ee94b97SJan Kryl 			} else {
38109ee94b97SJan Kryl 				NDMP_LOG(LOG_ERR, "Tape read error: %m.");
38119ee94b97SJan Kryl 				return (TAPE_READ_ERR);
38129ee94b97SJan Kryl 			}
38139ee94b97SJan Kryl 		} else if (n > 0) {
38149ee94b97SJan Kryl 			NS_ADD(rtape, n);
38159ee94b97SJan Kryl 			data += n;
38169ee94b97SJan Kryl 			count -= n;
38179ee94b97SJan Kryl 			session->ns_tape.td_record_count++;
38189ee94b97SJan Kryl 		} else {
38192654012fSReza Sabdar 			if (!is_writer_running_v3(session))
38202654012fSReza Sabdar 				return (TAPE_NO_WRITER_ERR);
38212654012fSReza Sabdar 
38222654012fSReza Sabdar 			/*
38239ee94b97SJan Kryl 			 * End of file or media reached. Notify client and
38249ee94b97SJan Kryl 			 * wait for the client to either abort the data
38259ee94b97SJan Kryl 			 * operation or continue the operation after changing
38269ee94b97SJan Kryl 			 * the tape.
38272654012fSReza Sabdar 			 */
38289ee94b97SJan Kryl 			if (tape_is_at_bof(session)) {
38299ee94b97SJan Kryl 				NDMP_LOG(LOG_DEBUG, "EOT detected");
38309ee94b97SJan Kryl 				pause_reason = NDMP_MOVER_PAUSE_EOM;
38319ee94b97SJan Kryl 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
38329ee94b97SJan Kryl 				    ++ndmp_log_msg_id, "End of medium reached");
38339ee94b97SJan Kryl 			} else {
38349ee94b97SJan Kryl 				NDMP_LOG(LOG_DEBUG, "EOF detected");
38359ee94b97SJan Kryl 				/* reposition the tape to BOT side of FM */
38369ee94b97SJan Kryl 				fm_dance(session);
38379ee94b97SJan Kryl 				pause_reason = NDMP_MOVER_PAUSE_EOF;
38389ee94b97SJan Kryl 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
38399ee94b97SJan Kryl 				    ++ndmp_log_msg_id, "End of file reached.");
38409ee94b97SJan Kryl 			}
38419ee94b97SJan Kryl 		}
38422654012fSReza Sabdar 
38439ee94b97SJan Kryl 		if (pause_reason != NDMP_MOVER_PAUSE_NA) {
38449ee94b97SJan Kryl 			err = mover_pause_v3(session, pause_reason);
38452654012fSReza Sabdar 
38462654012fSReza Sabdar 			/* Operation aborted or connection terminated? */
38472654012fSReza Sabdar 			if (err < 0) {
38482654012fSReza Sabdar 				return (0);
38492654012fSReza Sabdar 			}
38509ee94b97SJan Kryl 			/* Retry the read from new location */
38512654012fSReza Sabdar 		}
38522654012fSReza Sabdar 	}
38539ee94b97SJan Kryl 	return (session->ns_mover.md_record_size);
38542654012fSReza Sabdar }
38552654012fSReza Sabdar 
38562654012fSReza Sabdar 
38572654012fSReza Sabdar /*
38582654012fSReza Sabdar  * mover_data_write_v3
38592654012fSReza Sabdar  *
38602654012fSReza Sabdar  * Reads backup data from the tape device and writes the
38612654012fSReza Sabdar  * data to the data connection.
38622654012fSReza Sabdar  * This function is called by ndmpd_select when the data connection
38632654012fSReza Sabdar  * is ready for more data to be written.
38642654012fSReza Sabdar  *
38652654012fSReza Sabdar  * Parameters:
38662654012fSReza Sabdar  *   cookie  (input) - session pointer.
38672654012fSReza Sabdar  *   fd      (input) - file descriptor.
38682654012fSReza Sabdar  *   mode    (input) - select mode.
38692654012fSReza Sabdar  *
38702654012fSReza Sabdar  * Returns:
38712654012fSReza Sabdar  *   void.
38722654012fSReza Sabdar  */
38732654012fSReza Sabdar /*ARGSUSED*/
38742654012fSReza Sabdar static void
mover_data_write_v3(void * cookie,int fd,ulong_t mode)38752654012fSReza Sabdar mover_data_write_v3(void *cookie, int fd, ulong_t mode)
38762654012fSReza Sabdar {
38772654012fSReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
38782654012fSReza Sabdar 	int n;
38792654012fSReza Sabdar 	ulong_t len;
38802654012fSReza Sabdar 	u_longlong_t wlen;
38812654012fSReza Sabdar 	ndmp_notify_mover_paused_request pause_request;
38822654012fSReza Sabdar 
38832654012fSReza Sabdar 	/*
38842654012fSReza Sabdar 	 * If the end of the mover window has been reached,
38852654012fSReza Sabdar 	 * then notify the client that a seek is needed.
38862654012fSReza Sabdar 	 * Remove the file handler to prevent this function from
38872654012fSReza Sabdar 	 * being called. The handler will be reinstalled in
38882654012fSReza Sabdar 	 * ndmpd_mover_continue.
38892654012fSReza Sabdar 	 */
38902654012fSReza Sabdar 	if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
38912654012fSReza Sabdar 	    + session->ns_mover.md_window_length) {
38922654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
38932654012fSReza Sabdar 		    "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
38942654012fSReza Sabdar 
38952654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
38962654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
38972654012fSReza Sabdar 
38982654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
38992654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
39002654012fSReza Sabdar 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
39012654012fSReza Sabdar 		pause_request.seek_position =
39022654012fSReza Sabdar 		    long_long_to_quad(session->ns_mover.md_position);
39032654012fSReza Sabdar 		session->ns_mover.md_seek_position =
39042654012fSReza Sabdar 		    session->ns_mover.md_position;
39052654012fSReza Sabdar 
39062654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session, fd);
39072654012fSReza Sabdar 
39082654012fSReza Sabdar 		if (ndmp_send_request(session->ns_connection,
39092654012fSReza Sabdar 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
39102654012fSReza Sabdar 		    (void *)&pause_request, 0) < 0) {
39112654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
39122654012fSReza Sabdar 			    "Sending notify_mover_paused request");
39132654012fSReza Sabdar 			ndmpd_mover_error(session,
39142654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
39152654012fSReza Sabdar 		}
39162654012fSReza Sabdar 		return;
39172654012fSReza Sabdar 	}
39182654012fSReza Sabdar 
39192654012fSReza Sabdar 	/*
39202654012fSReza Sabdar 	 * Read more data into the tape buffer if the buffer is empty.
39212654012fSReza Sabdar 	 */
39222654012fSReza Sabdar 	if (session->ns_mover.md_w_index == 0) {
39232654012fSReza Sabdar 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
39242654012fSReza Sabdar 
39252654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
39262654012fSReza Sabdar 		    "read %u bytes from tape", n);
39272654012fSReza Sabdar 
39282654012fSReza Sabdar 		if (n <= 0) {
39292654012fSReza Sabdar 			ndmpd_mover_error(session, (n == 0 ?
39302654012fSReza Sabdar 			    NDMP_MOVER_HALT_ABORTED
39312654012fSReza Sabdar 			    : NDMP_MOVER_HALT_MEDIA_ERROR));
39322654012fSReza Sabdar 			return;
39332654012fSReza Sabdar 		}
39342654012fSReza Sabdar 
39352654012fSReza Sabdar 		/*
39362654012fSReza Sabdar 		 * Discard data if the current data stream position is
39372654012fSReza Sabdar 		 * prior to the seek position. This is necessary if a seek
39382654012fSReza Sabdar 		 * request set the seek pointer to a position that is not a
39392654012fSReza Sabdar 		 * record boundary. The seek request handler can only position
39402654012fSReza Sabdar 		 * to the start of a record.
39412654012fSReza Sabdar 		 */
39422654012fSReza Sabdar 		if (session->ns_mover.md_position <
39432654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
39442654012fSReza Sabdar 			session->ns_mover.md_r_index =
39452654012fSReza Sabdar 			    session->ns_mover.md_seek_position -
39462654012fSReza Sabdar 			    session->ns_mover.md_position;
39472654012fSReza Sabdar 			session->ns_mover.md_position =
39482654012fSReza Sabdar 			    session->ns_mover.md_seek_position;
39492654012fSReza Sabdar 		}
39502654012fSReza Sabdar 
39512654012fSReza Sabdar 		session->ns_mover.md_w_index = n;
39529ee94b97SJan Kryl 		session->ns_mover.md_record_num++;
39532654012fSReza Sabdar 	}
39542654012fSReza Sabdar 
39552654012fSReza Sabdar 	/*
39562654012fSReza Sabdar 	 * The limit on the total amount of data to be sent can be
39572654012fSReza Sabdar 	 * dictated by either the end of the mover window or the end of the
39582654012fSReza Sabdar 	 * seek window.
39592654012fSReza Sabdar 	 * First determine which window applies and then determine if the
39602654012fSReza Sabdar 	 * send length needs to be less than a full record to avoid
39612654012fSReza Sabdar 	 * exceeding the window.
39622654012fSReza Sabdar 	 */
39632654012fSReza Sabdar 	if (session->ns_mover.md_position +
39642654012fSReza Sabdar 	    session->ns_mover.md_bytes_left_to_read >
39652654012fSReza Sabdar 	    session->ns_mover.md_window_offset +
39662654012fSReza Sabdar 	    session->ns_mover.md_window_length)
39672654012fSReza Sabdar 		wlen = session->ns_mover.md_window_offset +
39682654012fSReza Sabdar 		    session->ns_mover.md_window_length -
39692654012fSReza Sabdar 		    session->ns_mover.md_position;
39702654012fSReza Sabdar 	else
39712654012fSReza Sabdar 		wlen = session->ns_mover.md_bytes_left_to_read;
39722654012fSReza Sabdar 
39732654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
39742654012fSReza Sabdar 
39752654012fSReza Sabdar 	/*
39762654012fSReza Sabdar 	 * Now limit the length to the amount of data in the buffer.
39772654012fSReza Sabdar 	 */
39782654012fSReza Sabdar 	if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
39792654012fSReza Sabdar 		wlen = session->ns_mover.md_w_index -
39802654012fSReza Sabdar 		    session->ns_mover.md_r_index;
39812654012fSReza Sabdar 
39822654012fSReza Sabdar 	len = wlen & 0xffffffff;
39832654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG,
39842654012fSReza Sabdar 	    "buffer restrictions: wlen %llu len %u", wlen, len);
39852654012fSReza Sabdar 
39862654012fSReza Sabdar 	/*
39872654012fSReza Sabdar 	 * Write the data to the data connection.
39882654012fSReza Sabdar 	 */
39892654012fSReza Sabdar 	n = write(session->ns_mover.md_sock,
39902654012fSReza Sabdar 	    &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
39912654012fSReza Sabdar 
39922654012fSReza Sabdar 	if (n < 0) {
399397f7c475SJan Kryl 		/* Socket is non-blocking, perhaps the write queue is full */
399497f7c475SJan Kryl 		if (errno == EAGAIN) {
399597f7c475SJan Kryl 			NDMP_LOG(LOG_ERR, "Cannot write to socket");
39962654012fSReza Sabdar 			return;
39972654012fSReza Sabdar 		}
399897f7c475SJan Kryl 		NDMP_LOG(LOG_ERR, "Failed to write to socket: %m");
39992654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
40002654012fSReza Sabdar 		return;
40012654012fSReza Sabdar 	}
40022654012fSReza Sabdar 
40032654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG,
40042654012fSReza Sabdar 	    "wrote %u of %u bytes to data connection position %llu r_index %lu",
40052654012fSReza Sabdar 	    n, len, session->ns_mover.md_position,
40062654012fSReza Sabdar 	    session->ns_mover.md_r_index);
40072654012fSReza Sabdar 
40082654012fSReza Sabdar 	session->ns_mover.md_r_index += n;
40092654012fSReza Sabdar 	session->ns_mover.md_position += n;
40102654012fSReza Sabdar 	session->ns_mover.md_bytes_left_to_read -= n;
40112654012fSReza Sabdar 
40122654012fSReza Sabdar 	/*
40132654012fSReza Sabdar 	 * If all data in the buffer has been written,
40142654012fSReza Sabdar 	 * zero the buffer indices. The next call to this function
40152654012fSReza Sabdar 	 * will read more data from the tape device into the buffer.
40162654012fSReza Sabdar 	 */
40172654012fSReza Sabdar 	if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
40182654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
40192654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
40202654012fSReza Sabdar 	}
40212654012fSReza Sabdar 
40222654012fSReza Sabdar 	/*
40232654012fSReza Sabdar 	 * If the read limit has been reached,
40242654012fSReza Sabdar 	 * then remove the file handler to prevent this
40252654012fSReza Sabdar 	 * function from getting called. The next mover_read request
40262654012fSReza Sabdar 	 * will reinstall the handler.
40272654012fSReza Sabdar 	 */
40282654012fSReza Sabdar 	if (session->ns_mover.md_bytes_left_to_read == 0)
40292654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session, fd);
40302654012fSReza Sabdar }
40312654012fSReza Sabdar 
40322654012fSReza Sabdar 
40332654012fSReza Sabdar /*
40342654012fSReza Sabdar  * accept_connection_v3
40352654012fSReza Sabdar  *
40362654012fSReza Sabdar  * Accept a data connection from a data server.
40372654012fSReza Sabdar  * Called by ndmpd_select when a connection is pending on
40382654012fSReza Sabdar  * the mover listen socket.
40392654012fSReza Sabdar  *
40402654012fSReza Sabdar  * Parameters:
40412654012fSReza Sabdar  *   cookie  (input) - session pointer.
40422654012fSReza Sabdar  *   fd      (input) - file descriptor.
40432654012fSReza Sabdar  *   mode    (input) - select mode.
40442654012fSReza Sabdar  *
40452654012fSReza Sabdar  * Returns:
40462654012fSReza Sabdar  *   void.
40472654012fSReza Sabdar  */
40482654012fSReza Sabdar /*ARGSUSED*/
40492654012fSReza Sabdar static void
accept_connection_v3(void * cookie,int fd,ulong_t mode)40502654012fSReza Sabdar accept_connection_v3(void *cookie, int fd, ulong_t mode)
40512654012fSReza Sabdar {
40522654012fSReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
40532654012fSReza Sabdar 	int from_len;
40542654012fSReza Sabdar 	struct sockaddr_in from;
40552654012fSReza Sabdar 
40562654012fSReza Sabdar 	from_len = sizeof (from);
40572654012fSReza Sabdar 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
40582654012fSReza Sabdar 	    &from_len);
40592654012fSReza Sabdar 
40602654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
40612654012fSReza Sabdar 	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
40622654012fSReza Sabdar 
40632654012fSReza Sabdar 	(void) ndmpd_remove_file_handler(session, fd);
40642654012fSReza Sabdar 	(void) close(session->ns_mover.md_listen_sock);
40652654012fSReza Sabdar 	session->ns_mover.md_listen_sock = -1;
40662654012fSReza Sabdar 
40672654012fSReza Sabdar 	if (session->ns_mover.md_sock < 0) {
40682654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
40692654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
40702654012fSReza Sabdar 		return;
40712654012fSReza Sabdar 	}
40722654012fSReza Sabdar 
40732654012fSReza Sabdar 	/*
40742654012fSReza Sabdar 	 * Save the peer address.
40752654012fSReza Sabdar 	 */
40762654012fSReza Sabdar 	session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
40772654012fSReza Sabdar 	session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
40782654012fSReza Sabdar 
407997f7c475SJan Kryl 	/* Set the parameter of the new socket */
408097f7c475SJan Kryl 	set_socket_options(session->ns_mover.md_sock);
408197f7c475SJan Kryl 
40822654012fSReza Sabdar 	/*
408397f7c475SJan Kryl 	 * Backup/restore is handled by a callback called from main event loop,
408497f7c475SJan Kryl 	 * which reads/writes data to md_sock socket. IO on socket must be
408597f7c475SJan Kryl 	 * non-blocking, otherwise ndmpd would be unable to process other
408697f7c475SJan Kryl 	 * incoming requests.
40872654012fSReza Sabdar 	 */
408897f7c475SJan Kryl 	if (!set_socket_nonblock(session->ns_mover.md_sock)) {
408997f7c475SJan Kryl 		NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
409097f7c475SJan Kryl 		    "on socket: %m");
409197f7c475SJan Kryl 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
409297f7c475SJan Kryl 		return;
409397f7c475SJan Kryl 	}
40942654012fSReza Sabdar 
40952654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
40962654012fSReza Sabdar 
40972654012fSReza Sabdar 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
40982654012fSReza Sabdar 		if (ndmpd_add_file_handler(session, (void*)session,
40992654012fSReza Sabdar 		    session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
41002654012fSReza Sabdar 		    HC_MOVER, mover_data_read_v3) < 0) {
41012654012fSReza Sabdar 			ndmpd_mover_error(session,
41022654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
41032654012fSReza Sabdar 			return;
41042654012fSReza Sabdar 		}
41052654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
41062654012fSReza Sabdar 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
41072654012fSReza Sabdar 		    ntohs(from.sin_port));
41082654012fSReza Sabdar 	} else {
41092654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
41102654012fSReza Sabdar 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
41112654012fSReza Sabdar 		    ntohs(from.sin_port));
41122654012fSReza Sabdar 	}
41132654012fSReza Sabdar 
41142654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
41152654012fSReza Sabdar }
41162654012fSReza Sabdar 
41172654012fSReza Sabdar 
41182654012fSReza Sabdar /*
41192654012fSReza Sabdar  * create_listen_socket_v3
41202654012fSReza Sabdar  *
41212654012fSReza Sabdar  * Creates a socket for listening for accepting data connections.
41222654012fSReza Sabdar  *
41232654012fSReza Sabdar  * Parameters:
41242654012fSReza Sabdar  *   session (input)  - session pointer.
41252654012fSReza Sabdar  *   addr    (output) - location to store address of socket.
41262654012fSReza Sabdar  *   port    (output) - location to store port of socket.
41272654012fSReza Sabdar  *
41282654012fSReza Sabdar  * Returns:
41292654012fSReza Sabdar  *   0 - success.
41302654012fSReza Sabdar  *  -1 - error.
41312654012fSReza Sabdar  */
41322654012fSReza Sabdar static int
create_listen_socket_v3(ndmpd_session_t * session,ulong_t * addr,ushort_t * port)41332654012fSReza Sabdar create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
41342654012fSReza Sabdar {
41352654012fSReza Sabdar 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
41362654012fSReza Sabdar 	if (session->ns_mover.md_listen_sock < 0)
41372654012fSReza Sabdar 		return (-1);
41382654012fSReza Sabdar 
41392654012fSReza Sabdar 	/*
41402654012fSReza Sabdar 	 * Add a file handler for the listen socket.
41412654012fSReza Sabdar 	 * ndmpd_select will call accept_connection when a
41422654012fSReza Sabdar 	 * connection is ready to be accepted.
41432654012fSReza Sabdar 	 */
41442654012fSReza Sabdar 	if (ndmpd_add_file_handler(session, (void *) session,
41452654012fSReza Sabdar 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
41462654012fSReza Sabdar 	    accept_connection_v3) < 0) {
41472654012fSReza Sabdar 		(void) close(session->ns_mover.md_listen_sock);
41482654012fSReza Sabdar 		session->ns_mover.md_listen_sock = -1;
41492654012fSReza Sabdar 		return (-1);
41502654012fSReza Sabdar 	}
41512654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "IP %s port %d",
41522654012fSReza Sabdar 	    inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
41532654012fSReza Sabdar 	return (0);
41542654012fSReza Sabdar }
41552654012fSReza Sabdar 
41562654012fSReza Sabdar 
41572654012fSReza Sabdar /*
415897f7c475SJan Kryl  * mover_connect_sock
41592654012fSReza Sabdar  *
41602654012fSReza Sabdar  * Connect the mover to the specified address
41612654012fSReza Sabdar  *
41622654012fSReza Sabdar  * Parameters:
41632654012fSReza Sabdar  *   session (input)  - session pointer.
41642654012fSReza Sabdar  *   mode    (input)  - mover mode.
41652654012fSReza Sabdar  *   addr    (output) - location to store address of socket.
41662654012fSReza Sabdar  *   port    (output) - location to store port of socket.
41672654012fSReza Sabdar  *
41682654012fSReza Sabdar  * Returns:
41692654012fSReza Sabdar  *   error code.
41702654012fSReza Sabdar  */
41712654012fSReza Sabdar static ndmp_error
mover_connect_sock(ndmpd_session_t * session,ndmp_mover_mode mode,ulong_t addr,ushort_t port)417297f7c475SJan Kryl mover_connect_sock(ndmpd_session_t *session, ndmp_mover_mode mode,
41732654012fSReza Sabdar     ulong_t addr, ushort_t port)
41742654012fSReza Sabdar {
41752654012fSReza Sabdar 	int sock;
41762654012fSReza Sabdar 
41772654012fSReza Sabdar 	sock = ndmp_connect_sock_v3(addr, port);
41782654012fSReza Sabdar 	if (sock < 0)
41792654012fSReza Sabdar 		return (NDMP_CONNECT_ERR);
41802654012fSReza Sabdar 
418197f7c475SJan Kryl 	/*
418297f7c475SJan Kryl 	 * Backup/restore is handled by a callback called from main event loop,
418397f7c475SJan Kryl 	 * which reads/writes data to md_sock socket. IO on socket must be
418497f7c475SJan Kryl 	 * non-blocking, otherwise ndmpd would be unable to process other
418597f7c475SJan Kryl 	 * incoming requests.
418697f7c475SJan Kryl 	 */
418797f7c475SJan Kryl 	if (!set_socket_nonblock(sock)) {
418897f7c475SJan Kryl 		NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
418997f7c475SJan Kryl 		    "on socket: %m");
419097f7c475SJan Kryl 		(void) close(sock);
419197f7c475SJan Kryl 		return (NDMP_CONNECT_ERR);
419297f7c475SJan Kryl 	}
419397f7c475SJan Kryl 
41942654012fSReza Sabdar 	if (mode == NDMP_MOVER_MODE_READ) {
41952654012fSReza Sabdar 		if (ndmpd_add_file_handler(session, (void*)session, sock,
41962654012fSReza Sabdar 		    NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
41972654012fSReza Sabdar 			(void) close(sock);
41982654012fSReza Sabdar 			return (NDMP_CONNECT_ERR);
41992654012fSReza Sabdar 		}
42002654012fSReza Sabdar 	}
42012654012fSReza Sabdar 	session->ns_mover.md_sock = sock;
42022654012fSReza Sabdar 	session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
42032654012fSReza Sabdar 	session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
42042654012fSReza Sabdar 	session->ns_mover.md_data_addr.tcp_port_v3 = port;
42052654012fSReza Sabdar 	return (NDMP_NO_ERR);
42062654012fSReza Sabdar }
42072654012fSReza Sabdar 
42082654012fSReza Sabdar 
42092654012fSReza Sabdar /*
42102654012fSReza Sabdar  * ndmpd_local_read_v3
42112654012fSReza Sabdar  *
42122654012fSReza Sabdar  * Reads data from the local tape device.
42132654012fSReza Sabdar  * Full tape records are read and buffered.
42142654012fSReza Sabdar  *
42152654012fSReza Sabdar  * Parameters:
42162654012fSReza Sabdar  *   session (input) - session pointer.
42172654012fSReza Sabdar  *   data    (input) - location to store data.
42182654012fSReza Sabdar  *   length  (input) - data length.
42192654012fSReza Sabdar  *
42202654012fSReza Sabdar  * Returns:
42212654012fSReza Sabdar  *   1 - no read error but no writer running
42222654012fSReza Sabdar  *   0 - data successfully read.
42232654012fSReza Sabdar  *  -1 - error.
42242654012fSReza Sabdar  */
42252654012fSReza Sabdar int
ndmpd_local_read_v3(ndmpd_session_t * session,char * data,ulong_t length)42262654012fSReza Sabdar ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
42272654012fSReza Sabdar {
42282654012fSReza Sabdar 	ulong_t count;
42292654012fSReza Sabdar 	ulong_t len;
42302654012fSReza Sabdar 	ssize_t n;
42312654012fSReza Sabdar 
42322654012fSReza Sabdar 	count = 0;
42332654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
42342654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
42352654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
42362654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
42372654012fSReza Sabdar 		return (-1);
42382654012fSReza Sabdar 	}
42392654012fSReza Sabdar 
42402654012fSReza Sabdar 	/*
42412654012fSReza Sabdar 	 * Automatically increase the seek window if necessary.
42422654012fSReza Sabdar 	 * This is needed in the event the module attempts to read
42432654012fSReza Sabdar 	 * past a seek window set via a prior call to ndmpd_seek() or
42442654012fSReza Sabdar 	 * the module has not issued a seek. If no seek was issued then
42452654012fSReza Sabdar 	 * pretend that a seek was issued to read the entire tape.
42462654012fSReza Sabdar 	 */
42472654012fSReza Sabdar 	if (length > session->ns_mover.md_bytes_left_to_read) {
42482654012fSReza Sabdar 		/* ndmpd_seek() never called? */
42492654012fSReza Sabdar 		if (session->ns_data.dd_read_length == 0) {
42502654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read = ~0LL;
42512654012fSReza Sabdar 			session->ns_data.dd_read_offset = 0LL;
42522654012fSReza Sabdar 			session->ns_data.dd_read_length = ~0LL;
42532654012fSReza Sabdar 		} else {
42542654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read = length;
42552654012fSReza Sabdar 			session->ns_data.dd_read_offset =
42562654012fSReza Sabdar 			    session->ns_mover.md_position;
42572654012fSReza Sabdar 			session->ns_data.dd_read_length = length;
42582654012fSReza Sabdar 		}
42592654012fSReza Sabdar 	}
42602654012fSReza Sabdar 
42612654012fSReza Sabdar 	/*
42622654012fSReza Sabdar 	 * Read as many records as necessary to satisfy the request.
42632654012fSReza Sabdar 	 */
42642654012fSReza Sabdar 	while (count < length) {
42652654012fSReza Sabdar 		/*
42662654012fSReza Sabdar 		 * If the end of the mover window has been reached,
42672654012fSReza Sabdar 		 * then notify the client that a new data window is needed.
42682654012fSReza Sabdar 		 */
42692654012fSReza Sabdar 		if (session->ns_mover.md_position >=
42702654012fSReza Sabdar 		    session->ns_mover.md_window_offset +
42712654012fSReza Sabdar 		    session->ns_mover.md_window_length) {
42722654012fSReza Sabdar 			if (mover_pause_v3(session,
42732654012fSReza Sabdar 			    NDMP_MOVER_PAUSE_SEEK) < 0) {
42742654012fSReza Sabdar 				ndmpd_mover_error(session,
42752654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
42762654012fSReza Sabdar 				return (-1);
42772654012fSReza Sabdar 			}
42782654012fSReza Sabdar 			continue;
42792654012fSReza Sabdar 		}
42802654012fSReza Sabdar 
42812654012fSReza Sabdar 		len = length - count;
42822654012fSReza Sabdar 
42832654012fSReza Sabdar 		/*
42842654012fSReza Sabdar 		 * Prevent reading past the end of the window.
42852654012fSReza Sabdar 		 */
42862654012fSReza Sabdar 		if (len > session->ns_mover.md_window_offset +
42872654012fSReza Sabdar 		    session->ns_mover.md_window_length -
42882654012fSReza Sabdar 		    session->ns_mover.md_position)
42892654012fSReza Sabdar 			len = session->ns_mover.md_window_offset +
42902654012fSReza Sabdar 			    session->ns_mover.md_window_length -
42912654012fSReza Sabdar 			    session->ns_mover.md_position;
42922654012fSReza Sabdar 
42932654012fSReza Sabdar 		/*
42942654012fSReza Sabdar 		 * Copy from the data buffer first.
42952654012fSReza Sabdar 		 */
42962654012fSReza Sabdar 		if (session->ns_mover.md_w_index -
42972654012fSReza Sabdar 		    session->ns_mover.md_r_index != 0) {
42982654012fSReza Sabdar 			/*
42992654012fSReza Sabdar 			 * Limit the copy to the amount of data in the buffer.
43002654012fSReza Sabdar 			 */
43012654012fSReza Sabdar 			if (len > session->ns_mover.md_w_index -
43022654012fSReza Sabdar 			    session->ns_mover.md_r_index)
43032654012fSReza Sabdar 				len = session->ns_mover.md_w_index -
43042654012fSReza Sabdar 				    session->ns_mover.md_r_index;
43052654012fSReza Sabdar 			(void) memcpy((void*)&data[count],
43062654012fSReza Sabdar 			    &session->ns_mover.md_buf[session->
43072654012fSReza Sabdar 			    ns_mover.md_r_index], len);
43082654012fSReza Sabdar 			count += len;
43092654012fSReza Sabdar 			session->ns_mover.md_r_index += len;
43102654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read -= len;
43112654012fSReza Sabdar 			session->ns_mover.md_position += len;
43122654012fSReza Sabdar 			continue;
43132654012fSReza Sabdar 		}
43142654012fSReza Sabdar 
43152654012fSReza Sabdar 		/*
43162654012fSReza Sabdar 		 * Determine if data needs to be buffered or
43172654012fSReza Sabdar 		 * can be read directly to user supplied location.
43182654012fSReza Sabdar 		 * We can fast path the read if at least a full record
43192654012fSReza Sabdar 		 * needs to be read and there is no seek pending.
43202654012fSReza Sabdar 		 * This is done to eliminate a buffer copy.
43212654012fSReza Sabdar 		 */
43222654012fSReza Sabdar 		if (len >= session->ns_mover.md_record_size &&
43232654012fSReza Sabdar 		    session->ns_mover.md_position >=
43242654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
43252654012fSReza Sabdar 			n = mover_tape_read_v3(session, &data[count]);
43262654012fSReza Sabdar 			if (n <= 0) {
43272654012fSReza Sabdar 				if (n == TAPE_NO_WRITER_ERR)
43282654012fSReza Sabdar 					return (1);
43292654012fSReza Sabdar 
43302654012fSReza Sabdar 				ndmpd_mover_error(session,
43312654012fSReza Sabdar 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
43322654012fSReza Sabdar 				    NDMP_MOVER_HALT_MEDIA_ERROR));
43332654012fSReza Sabdar 				return ((n == 0) ? 1 : -1);
43342654012fSReza Sabdar 			}
43352654012fSReza Sabdar 
43362654012fSReza Sabdar 			count += n;
43372654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read -= n;
43382654012fSReza Sabdar 			session->ns_mover.md_position += n;
43399ee94b97SJan Kryl 			session->ns_mover.md_record_num++;
43402654012fSReza Sabdar 			continue;
43412654012fSReza Sabdar 		}
43422654012fSReza Sabdar 
43432654012fSReza Sabdar 		/* Read the next record into the buffer. */
43442654012fSReza Sabdar 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
43452654012fSReza Sabdar 		if (n <= 0) {
43462654012fSReza Sabdar 			if (n == TAPE_NO_WRITER_ERR)
43472654012fSReza Sabdar 				return (1);
43482654012fSReza Sabdar 
43492654012fSReza Sabdar 			ndmpd_mover_error(session,
43502654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
43512654012fSReza Sabdar 			    NDMP_MOVER_HALT_MEDIA_ERROR));
43522654012fSReza Sabdar 			return ((n == 0) ? 1 : -1);
43532654012fSReza Sabdar 		}
43542654012fSReza Sabdar 
43552654012fSReza Sabdar 		session->ns_mover.md_w_index = n;
43562654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
43579ee94b97SJan Kryl 		session->ns_mover.md_record_num++;
43582654012fSReza Sabdar 
43592654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
43602654012fSReza Sabdar 
43612654012fSReza Sabdar 		/*
43622654012fSReza Sabdar 		 * Discard data if the current data stream position is
43632654012fSReza Sabdar 		 * prior to the seek position. This is necessary if a seek
43642654012fSReza Sabdar 		 * request set the seek pointer to a position that is not a
43652654012fSReza Sabdar 		 * record boundary. The seek request handler can only position
43662654012fSReza Sabdar 		 * to the start of a record.
43672654012fSReza Sabdar 		 */
43682654012fSReza Sabdar 		if (session->ns_mover.md_position <
43692654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
43702654012fSReza Sabdar 			session->ns_mover.md_r_index =
43712654012fSReza Sabdar 			    session->ns_mover.md_seek_position -
43722654012fSReza Sabdar 			    session->ns_mover.md_position;
43732654012fSReza Sabdar 			session->ns_mover.md_position =
43742654012fSReza Sabdar 			    session->ns_mover.md_seek_position;
43752654012fSReza Sabdar 		}
43762654012fSReza Sabdar 	}
43772654012fSReza Sabdar 
43782654012fSReza Sabdar 	return (0);
43792654012fSReza Sabdar }
4380