xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c (revision 9ee94b97c8654689d6a034daec08757fda75d21a)
1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * BSD 3 Clause License
7  *
8  * Copyright (c) 2007, The Storage Networking Industry Association.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 	- Redistributions of source code must retain the above copyright
14  *	  notice, this list of conditions and the following disclaimer.
15  *
16  * 	- Redistributions in binary form must reproduce the above copyright
17  *	  notice, this list of conditions and the following disclaimer in
18  *	  the documentation and/or other materials provided with the
19  *	  distribution.
20  *
21  *	- Neither the name of The Storage Networking Industry Association (SNIA)
22  *	  nor the names of its contributors may be used to endorse or promote
23  *	  products derived from this software without specific prior written
24  *	  permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc.  All rights reserved. */
41 
42 #include <sys/ioctl.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <net/if.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <netdb.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <string.h>
55 #include "ndmpd_common.h"
56 #include "ndmpd.h"
57 #include <sys/mtio.h>
58 
59 /*
60  * Maximum mover record size
61  */
62 #define	MAX_MOVER_RECSIZE	(512*KILOBYTE)
63 
64 static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
65     ushort_t *port);
66 static int tape_read(ndmpd_session_t *session, char *data);
67 static int change_tape(ndmpd_session_t *session);
68 static int discard_data(ndmpd_session_t *session, ulong_t length);
69 static int mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf);
70 static int mover_socket_write_one_buf(ndmpd_session_t *session,
71     tlm_buffer_t *buf);
72 static int start_mover_for_restore(ndmpd_session_t *session);
73 static int mover_socket_read_one_buf(ndmpd_session_t *session,
74     tlm_buffer_t *buf, long read_size);
75 static int mover_tape_write_one_buf(ndmpd_session_t *session,
76     tlm_buffer_t *buf);
77 static int start_mover_for_backup(ndmpd_session_t *session);
78 static boolean_t is_writer_running_v3(ndmpd_session_t *session);
79 static int mover_pause_v3(ndmpd_session_t *session,
80     ndmp_mover_pause_reason reason);
81 static int mover_tape_write_v3(ndmpd_session_t *session, char *data,
82     ssize_t length);
83 static int mover_tape_flush_v3(ndmpd_session_t *session);
84 static int mover_tape_read_v3(ndmpd_session_t *session, char *data);
85 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
86     ushort_t *port);
87 static void mover_data_read_v3(void *cookie, int fd, ulong_t mode);
88 static void accept_connection(void *cookie, int fd, ulong_t mode);
89 static void mover_data_write_v3(void *cookie, int fd, ulong_t mode);
90 static void accept_connection_v3(void *cookie, int fd, ulong_t mode);
91 static ndmp_error mover_connect_sock_v3(ndmpd_session_t *session,
92     ndmp_mover_mode mode, ulong_t addr, ushort_t port);
93 static boolean_t is_writer_running(ndmpd_session_t *session);
94 
95 
96 int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
97 
98 #define	TAPE_READ_ERR		-1
99 #define	TAPE_NO_WRITER_ERR	-2
100 
101 /*
102  * ************************************************************************
103  * NDMP V2 HANDLERS
104  * ************************************************************************
105  */
106 
107 /*
108  * ndmpd_mover_get_state_v2
109  *
110  * This handler handles the mover_get_state request.
111  * Status information for the mover state machine is returned.
112  *
113  * Parameters:
114  *   connection (input) - connection handle.
115  *   body       (input) - request message body.
116  *
117  * Returns:
118  *   void
119  */
120 /*ARGSUSED*/
121 void
122 ndmpd_mover_get_state_v2(ndmp_connection_t *connection, void *body)
123 {
124 	ndmp_mover_get_state_reply_v2 reply;
125 	ndmpd_session_t *session = ndmp_get_client_data(connection);
126 
127 	reply.error = NDMP_NO_ERR;
128 	reply.state = session->ns_mover.md_state;
129 	reply.pause_reason = session->ns_mover.md_pause_reason;
130 	reply.halt_reason = session->ns_mover.md_halt_reason;
131 	reply.record_size = session->ns_mover.md_record_size;
132 	reply.record_num = session->ns_mover.md_record_num;
133 	reply.data_written =
134 	    long_long_to_quad(session->ns_mover.md_data_written);
135 	reply.seek_position =
136 	    long_long_to_quad(session->ns_mover.md_seek_position);
137 	reply.bytes_left_to_read =
138 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
139 	reply.window_offset =
140 	    long_long_to_quad(session->ns_mover.md_window_offset);
141 	reply.window_length =
142 	    long_long_to_quad(session->ns_mover.md_window_length);
143 
144 	ndmp_send_reply(connection, (void *) &reply,
145 	    "sending tape_get_state reply");
146 }
147 
148 
149 /*
150  * ndmpd_mover_listen_v2
151  *
152  * This handler handles mover_listen requests.
153  *
154  * Parameters:
155  *   connection (input) - connection handle.
156  *   body       (input) - request message body.
157  *
158  * Returns:
159  *   void
160  */
161 void
162 ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
163 {
164 	ndmp_mover_listen_request_v2 *request;
165 	ndmp_mover_listen_reply_v2 reply;
166 	ndmpd_session_t *session = ndmp_get_client_data(connection);
167 	ulong_t addr;
168 	ushort_t port;
169 
170 	request = (ndmp_mover_listen_request_v2 *)body;
171 
172 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
173 	    session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
174 		NDMP_LOG(LOG_DEBUG, "Invalid state");
175 		reply.error = NDMP_ILLEGAL_STATE_ERR;
176 		ndmp_send_reply(connection, (void *) &reply,
177 		    "sending mover_listen reply");
178 		return;
179 	}
180 	session->ns_mover.md_mode = request->mode;
181 
182 	if (request->addr_type == NDMP_ADDR_LOCAL) {
183 		reply.mover.addr_type = NDMP_ADDR_LOCAL;
184 	} else {
185 		if (create_listen_socket_v2(session, &addr, &port) < 0) {
186 			reply.error = NDMP_IO_ERR;
187 			ndmp_send_reply(connection, (void *) &reply,
188 			    "sending mover_listen reply");
189 			return;
190 		}
191 		reply.mover.addr_type = NDMP_ADDR_TCP;
192 		reply.mover.ndmp_mover_addr_u.addr.ip_addr = htonl(addr);
193 		reply.mover.ndmp_mover_addr_u.addr.port = htons(port);
194 	}
195 
196 	session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
197 
198 	/*
199 	 * ndmp window should always set by client during restore
200 	 */
201 
202 	/* Set the default window. */
203 	session->ns_mover.md_window_offset = 0;
204 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
205 	session->ns_mover.md_position = 0;
206 
207 	reply.error = NDMP_NO_ERR;
208 	ndmp_send_reply(connection, (void *) &reply,
209 	    "sending mover_listen reply");
210 }
211 
212 
213 /*
214  * ndmpd_mover_continue_v2
215  *
216  * This handler handles mover_continue requests.
217  *
218  * Parameters:
219  *   connection (input) - connection handle.
220  *   body       (input) - request message body.
221  *
222  * Returns:
223  *   void
224  */
225 /*ARGSUSED*/
226 void
227 ndmpd_mover_continue_v2(ndmp_connection_t *connection, void *body)
228 {
229 	ndmp_mover_continue_reply reply;
230 	ndmpd_session_t *session = ndmp_get_client_data(connection);
231 
232 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
233 		NDMP_LOG(LOG_DEBUG, "Invalid state");
234 
235 		reply.error = NDMP_ILLEGAL_STATE_ERR;
236 		ndmp_send_reply(connection, (void *) &reply,
237 		    "sending mover_continue reply");
238 		return;
239 	}
240 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
241 	reply.error = NDMP_NO_ERR;
242 	ndmp_send_reply(connection, (void *) &reply,
243 	    "sending mover_continue reply");
244 }
245 
246 
247 /*
248  * ndmpd_mover_abort_v2
249  *
250  * This handler handles mover_abort requests.
251  *
252  * Parameters:
253  *   connection (input) - connection handle.
254  *   body       (input) - request message body.
255  *
256  * Returns:
257  *   void
258  */
259 /*ARGSUSED*/
260 void
261 ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
262 {
263 	ndmp_mover_abort_reply reply;
264 	ndmpd_session_t *session = ndmp_get_client_data(connection);
265 
266 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
267 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
268 		NDMP_LOG(LOG_DEBUG, "Invalid state");
269 
270 		reply.error = NDMP_ILLEGAL_STATE_ERR;
271 		ndmp_send_reply(connection, (void *) &reply,
272 		    "sending mover_abort reply");
273 		return;
274 	}
275 
276 	reply.error = NDMP_NO_ERR;
277 	ndmp_send_reply(connection, (void *) &reply,
278 	    "sending mover_abort reply");
279 
280 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
281 
282 	nlp_event_nw(session);
283 	ndmp_stop_buffer_worker(session);
284 }
285 
286 
287 /*
288  * ndmpd_mover_stop_v2
289  *
290  * This handler handles mover_stop requests.
291  *
292  * Parameters:
293  *   connection (input) - connection handle.
294  *   body       (input) - request message body.
295  *
296  * Returns:
297  *   void
298  */
299 /*ARGSUSED*/
300 void
301 ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
302 {
303 	ndmp_mover_stop_reply reply;
304 	ndmpd_session_t *session = ndmp_get_client_data(connection);
305 
306 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {
307 		NDMP_LOG(LOG_DEBUG, "Invalid state");
308 
309 		reply.error = NDMP_ILLEGAL_STATE_ERR;
310 		ndmp_send_reply(connection, (void *) &reply,
311 		    "sending mover_stop reply");
312 		return;
313 	}
314 
315 	ndmp_waitfor_op(session);
316 	reply.error = NDMP_NO_ERR;
317 	ndmp_send_reply(connection, (void *) &reply,
318 	    "sending mover_stop reply");
319 
320 	ndmp_lbr_cleanup(session);
321 	ndmpd_mover_cleanup(session);
322 	(void) ndmpd_mover_init(session);
323 	(void) ndmp_lbr_init(session);
324 }
325 
326 
327 /*
328  * ndmpd_mover_set_window_v2
329  *
330  * This handler handles mover_set_window requests.
331  *
332  *
333  * Parameters:
334  *   connection (input) - connection handle.
335  *   body       (input) - request message body.
336  *
337  * Returns:
338  *   void
339  */
340 void
341 ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
342 {
343 	ndmp_mover_set_window_request *request;
344 	ndmp_mover_set_window_reply reply;
345 	ndmpd_session_t *session = ndmp_get_client_data(connection);
346 
347 	request = (ndmp_mover_set_window_request *) body;
348 
349 	/*
350 	 * The NDMPv2 specification states that "a window can be set only
351 	 * when in the listen or paused state."
352 	 *
353 	 * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
354 	 * allowing it in the idle state as well.
355 	 */
356 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
357 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
358 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
359 		reply.error = NDMP_ILLEGAL_STATE_ERR;
360 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
361 		    session->ns_mover.md_state);
362 	} else {
363 		if (quad_to_long_long(request->length) == 0) {
364 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
365 			NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
366 			    quad_to_long_long(request->length));
367 		} else {
368 			reply.error = NDMP_NO_ERR;
369 			session->ns_mover.md_window_offset =
370 			    quad_to_long_long(request->offset);
371 			session->ns_mover.md_window_length =
372 			    quad_to_long_long(request->length);
373 			session->ns_mover.md_position =
374 			    session->ns_mover.md_window_offset;
375 		}
376 	}
377 
378 	ndmp_send_reply(connection, (void *) &reply,
379 	    "sending mover_set_window reply");
380 }
381 
382 
383 /*
384  * ndmpd_mover_read_v2
385  *
386  * This handler handles mover_read requests. If the requested offset is
387  * outside of the current window, the mover is paused and a notify_mover_paused
388  * request is sent notifying the client that a seek is required. If the
389  * requested offest is within the window but not within the current record,
390  * then the tape is positioned to the record containing the requested offest.
391  * The requested amount of data is then read from the tape device and written
392  * to the data connection.
393  *
394  * Parameters:
395  *   connection (input) - connection handle.
396  *   body       (input) - request message body.
397  *
398  * Returns:
399  *   void
400  */
401 void
402 ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
403 {
404 	ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
405 	ndmp_mover_read_reply reply;
406 	ndmpd_session_t *session = ndmp_get_client_data(connection);
407 	int err;
408 
409 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
410 	    session->ns_mover.md_bytes_left_to_read != 0 ||
411 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
412 		NDMP_LOG(LOG_DEBUG, "Invalid state");
413 		reply.error = NDMP_ILLEGAL_STATE_ERR;
414 		ndmp_send_reply(connection, &reply,
415 		    "sending mover_read reply");
416 		return;
417 	}
418 	if (session->ns_tape.td_fd == -1) {
419 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
420 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
421 		ndmp_send_reply(connection, &reply,
422 		    "sending mover_read reply");
423 		return;
424 	}
425 
426 	reply.error = NDMP_NO_ERR;
427 	ndmp_send_reply(connection, &reply, "sending mover_read reply");
428 
429 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
430 	    quad_to_long_long(request->length));
431 	if (err < 0) {
432 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
433 		return;
434 	}
435 	/*
436 	 * Just return if we are waiting for the NDMP client to
437 	 * complete the seek.
438 	 */
439 	if (err == 1)
440 		return;
441 
442 	/*
443 	 * Start the mover for restore in the 3-way backups.
444 	 */
445 	if (start_mover_for_restore(session) < 0)
446 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
447 }
448 
449 
450 /*
451  * ndmpd_mover_close_v2
452  *
453  * This handler handles mover_close requests.
454  *
455  * Parameters:
456  *   connection (input) - connection handle.
457  *   body       (input) - request message body.
458  *
459  * Returns:
460  *   void
461  */
462 /*ARGSUSED*/
463 void
464 ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
465 {
466 	ndmp_mover_close_reply reply;
467 	ndmpd_session_t *session = ndmp_get_client_data(connection);
468 
469 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
470 		NDMP_LOG(LOG_DEBUG, "Invalid state");
471 
472 		reply.error = NDMP_ILLEGAL_STATE_ERR;
473 		ndmp_send_reply(connection, &reply,
474 		    "sending mover_close reply");
475 		return;
476 	}
477 	free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
478 
479 	reply.error = NDMP_NO_ERR;
480 	ndmp_send_reply(connection, &reply, "sending mover_close reply");
481 
482 	ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
483 }
484 
485 
486 /*
487  * ndmpd_mover_set_record_size_v2
488  *
489  * This handler handles mover_set_record_size requests.
490  *
491  * Parameters:
492  *   connection (input) - connection handle.
493  *   body       (input) - request message body.
494  *
495  * Returns:
496  *   void
497  */
498 void
499 ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
500 {
501 	ndmp_mover_set_record_size_request *request;
502 	ndmp_mover_set_record_size_reply reply;
503 	ndmpd_session_t *session = ndmp_get_client_data(connection);
504 
505 	request = (ndmp_mover_set_record_size_request *) body;
506 
507 	session->ns_mover.md_record_size = request->len;
508 	session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
509 	    request->len);
510 
511 	reply.error = NDMP_NO_ERR;
512 	ndmp_send_reply(connection, &reply,
513 	    "sending mover_set_record_size reply");
514 }
515 
516 
517 /*
518  * ************************************************************************
519  * NDMP V3 HANDLERS
520  * ************************************************************************
521  */
522 
523 /*
524  * ndmpd_mover_get_state_v3
525  *
526  * This handler handles the ndmp_mover_get_state_request.
527  * Status information for the mover state machine is returned.
528  *
529  * Parameters:
530  *   connection (input) - connection handle.
531  *   body       (input) - request message body.
532  *
533  * Returns:
534  *   void
535  */
536 /*ARGSUSED*/
537 void
538 ndmpd_mover_get_state_v3(ndmp_connection_t *connection, void *body)
539 {
540 	ndmp_mover_get_state_reply_v3 reply;
541 	ndmpd_session_t *session = ndmp_get_client_data(connection);
542 
543 	(void) memset((void*)&reply, 0, sizeof (reply));
544 
545 	reply.error = NDMP_NO_ERR;
546 	reply.state = session->ns_mover.md_state;
547 	reply.pause_reason = session->ns_mover.md_pause_reason;
548 	reply.halt_reason = session->ns_mover.md_halt_reason;
549 	reply.record_size = session->ns_mover.md_record_size;
550 	reply.record_num = session->ns_mover.md_record_num;
551 	reply.data_written =
552 	    long_long_to_quad(session->ns_mover.md_data_written);
553 	reply.seek_position =
554 	    long_long_to_quad(session->ns_mover.md_seek_position);
555 	reply.bytes_left_to_read =
556 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
557 	reply.window_offset =
558 	    long_long_to_quad(session->ns_mover.md_window_offset);
559 	reply.window_length =
560 	    long_long_to_quad(session->ns_mover.md_window_length);
561 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
562 		ndmp_copy_addr_v3(&reply.data_connection_addr,
563 		    &session->ns_mover.md_data_addr);
564 
565 	ndmp_send_reply(connection, &reply,
566 	    "sending ndmp_mover_get_state reply");
567 }
568 
569 
570 /*
571  * ndmpd_mover_listen_v3
572  *
573  * This handler handles ndmp_mover_listen_requests.
574  * A TCP/IP socket is created that is used to listen for
575  * and accept data connections initiated by a remote
576  * data server.
577  *
578  * Parameters:
579  *   connection (input) - connection handle.
580  *   body       (input) - request message body.
581  *
582  * Returns:
583  *   void
584  */
585 void
586 ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
587 {
588 	ndmp_mover_listen_request_v3 *request;
589 	ndmp_mover_listen_reply_v3 reply;
590 	ndmpd_session_t *session = ndmp_get_client_data(connection);
591 	ulong_t addr;
592 	ushort_t port;
593 
594 	request = (ndmp_mover_listen_request_v3 *)body;
595 
596 	(void) memset((void*)&reply, 0, sizeof (reply));
597 	reply.error = NDMP_NO_ERR;
598 
599 	if (request->mode != NDMP_MOVER_MODE_READ &&
600 	    request->mode != NDMP_MOVER_MODE_WRITE) {
601 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
602 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
603 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
604 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
605 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
606 		    request->addr_type);
607 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
608 		reply.error = NDMP_ILLEGAL_STATE_ERR;
609 		NDMP_LOG(LOG_DEBUG,
610 		    "Invalid mover state to process listen request");
611 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
612 		reply.error = NDMP_ILLEGAL_STATE_ERR;
613 		NDMP_LOG(LOG_DEBUG,
614 		    "Invalid data state to process listen request");
615 	} else if (session->ns_tape.td_fd == -1) {
616 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
617 		NDMP_LOG(LOG_DEBUG, "No tape device open");
618 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
619 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
620 		reply.error = NDMP_PERMISSION_ERR;
621 		NDMP_LOG(LOG_ERR, "Write protected device.");
622 	}
623 
624 	if (reply.error != NDMP_NO_ERR) {
625 		ndmp_send_reply(connection, &reply,
626 		    "error sending ndmp_mover_listen reply");
627 		return;
628 	}
629 
630 	switch (request->addr_type) {
631 	case NDMP_ADDR_LOCAL:
632 		reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
633 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
634 		reply.error = NDMP_NO_ERR;
635 		break;
636 	case NDMP_ADDR_TCP:
637 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
638 			reply.error = NDMP_IO_ERR;
639 			break;
640 		}
641 		reply.error = NDMP_NO_ERR;
642 		reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
643 		reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
644 		reply.data_connection_addr.tcp_port_v3 = htons(port);
645 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
646 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
647 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
648 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
649 		    session->ns_mover.md_listen_sock);
650 		break;
651 	default:
652 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
653 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
654 		    request->addr_type);
655 	}
656 
657 	if (reply.error == NDMP_NO_ERR) {
658 		session->ns_mover.md_mode = request->mode;
659 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
660 	}
661 
662 	ndmp_send_reply(connection, &reply,
663 	    "error sending ndmp_mover_listen reply");
664 }
665 
666 
667 /*
668  * ndmpd_mover_continue_v3
669  *
670  * This handler handles ndmp_mover_continue_requests.
671  *
672  * Parameters:
673  *   connection (input) - connection handle.
674  *   body       (input) - request message body.
675  *
676  * Returns:
677  *   void
678  */
679 /*ARGSUSED*/
680 void
681 ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
682 {
683 	ndmp_mover_continue_reply reply;
684 	ndmpd_session_t *session = ndmp_get_client_data(connection);
685 	int ret;
686 
687 	(void) memset((void*)&reply, 0, sizeof (reply));
688 
689 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
690 		NDMP_LOG(LOG_DEBUG, "Invalid state");
691 		reply.error = NDMP_ILLEGAL_STATE_ERR;
692 		ndmp_send_reply(connection, (void *) &reply,
693 		    "sending mover_continue reply");
694 		return;
695 	}
696 
697 	if (session->ns_protocol_version == NDMPV4 &&
698 	    !session->ns_mover.md_pre_cond) {
699 		NDMP_LOG(LOG_DEBUG, "Precondition check");
700 		reply.error = NDMP_PRECONDITION_ERR;
701 		ndmp_send_reply(connection, (void *) &reply,
702 		    "sending mover_continue reply");
703 		return;
704 	}
705 	/*
706 	 * Restore the file handler if the mover is remote to the data
707 	 * server and the handler was removed pending the continuation of a
708 	 * seek request. The handler is removed in mover_data_write().
709 	 */
710 	if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
711 	    session->ns_mover.md_sock != -1) {
712 		/*
713 		 * If we are here, it means that we needed DMA interference
714 		 * for seek. We should be on the right window, so we do not
715 		 * need the DMA interference anymore.
716 		 * We do another seek inside the Window to move to the
717 		 * exact position on the tape.
718 		 * If the resore is running without DAR the pause reason should
719 		 * not be seek.
720 		 */
721 		ret = ndmpd_mover_seek(session,
722 		    session->ns_mover.md_seek_position,
723 		    session->ns_mover.md_bytes_left_to_read);
724 		if (ret < 0) {
725 			ndmpd_mover_error(session,
726 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
727 			return;
728 		}
729 
730 		if (!ret) {
731 			if (ndmpd_add_file_handler(session, (void*) session,
732 			    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
733 			    HC_MOVER, mover_data_write_v3) < 0)
734 				ndmpd_mover_error(session,
735 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
736 		} else {
737 			/*
738 			 * This should not happen because we should be in the
739 			 * right window. This means that DMA does not follow
740 			 * the V3 spec.
741 			 */
742 			NDMP_LOG(LOG_DEBUG, "DMA Error.");
743 			ndmpd_mover_error(session,
744 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
745 			return;
746 		}
747 	}
748 
749 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
750 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
751 
752 	reply.error = NDMP_NO_ERR;
753 	ndmp_send_reply(connection, (void *) &reply,
754 	    "sending mover_continue reply");
755 }
756 
757 
758 /*
759  * ndmpd_mover_abort_v3
760  *
761  * This handler handles mover_abort requests.
762  *
763  * Parameters:
764  *   connection (input) - connection handle.
765  *   body       (input) - request message body.
766  *
767  * Returns:
768  *   void
769  */
770 /*ARGSUSED*/
771 void
772 ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
773 {
774 	ndmp_mover_abort_reply reply;
775 	ndmpd_session_t *session = ndmp_get_client_data(connection);
776 
777 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
778 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
779 		NDMP_LOG(LOG_DEBUG, "Invalid state");
780 
781 		reply.error = NDMP_ILLEGAL_STATE_ERR;
782 		ndmp_send_reply(connection, (void *) &reply,
783 		    "sending mover_abort reply");
784 		return;
785 	}
786 
787 	reply.error = NDMP_NO_ERR;
788 	ndmp_send_reply(connection, (void *) &reply,
789 	    "sending mover_abort reply");
790 
791 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
792 }
793 
794 
795 /*
796  * ndmpd_mover_set_window_v3
797  *
798  * This handler handles mover_set_window requests.
799  *
800  *
801  * Parameters:
802  *   connection (input) - connection handle.
803  *   body       (input) - request message body.
804  *
805  * Returns:
806  *   void
807  */
808 void
809 ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
810 {
811 	ndmp_mover_set_window_request *request;
812 	ndmp_mover_set_window_reply reply;
813 	ndmpd_session_t *session = ndmp_get_client_data(connection);
814 
815 	request = (ndmp_mover_set_window_request *) body;
816 
817 	/*
818 	 * Note: The spec says that the window can be set only in the listen
819 	 * and paused states.  We let this happen when mover is in the idle
820 	 * state as well.  I can't rememebr which NDMP client (net_backup 4.5
821 	 * or net_worker 6.1.1) forced us to do this!
822 	 */
823 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
824 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
825 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
826 		reply.error = NDMP_ILLEGAL_STATE_ERR;
827 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
828 		    session->ns_mover.md_state);
829 	} else if (session->ns_mover.md_record_size == 0) {
830 		if (session->ns_protocol_version == NDMPV4)
831 			reply.error = NDMP_PRECONDITION_ERR;
832 		else
833 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
834 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
835 	} else
836 		reply.error = NDMP_NO_ERR;
837 
838 	if (quad_to_long_long(request->length) == 0) {
839 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
840 		NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
841 		    quad_to_long_long(request->length));
842 	}
843 
844 	if (reply.error != NDMP_NO_ERR) {
845 		ndmp_send_reply(connection, (void *) &reply,
846 		    "sending mover_set_window_v3 reply");
847 		return;
848 	}
849 
850 	session->ns_mover.md_pre_cond = TRUE;
851 	session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
852 	session->ns_mover.md_window_length = quad_to_long_long(request->length);
853 
854 	/*
855 	 * We have to update the position for DAR. DAR needs this
856 	 * information to position to the right index on tape,
857 	 * especially when we span the tapes.
858 	 */
859 #ifdef	NO_POSITION_CHANGE
860 	/*
861 	 * Do not change the mover position if we are reading from
862 	 * the tape.  In this way, we can use the position+window_length
863 	 * to know how much we can write to a tape before pausing with
864 	 * EOW reason.
865 	 */
866 	if (session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE)
867 #endif	/* NO_POSITION_CHANGE */
868 		session->ns_mover.md_position =
869 		    session->ns_mover.md_window_offset;
870 
871 	ndmp_send_reply(connection, (void *) &reply,
872 	    "sending mover_set_window_v3 reply");
873 }
874 
875 
876 /*
877  * ndmpd_mover_read_v3
878  *
879  * This handler handles ndmp_mover_read_requests.
880  * If the requested offset is outside of the current window, the mover
881  * is paused and a notify_mover_paused request is sent notifying the
882  * client that a seek is required. If the requested offest is within
883  * the window but not within the current record, then the tape is
884  * positioned to the record containing the requested offest. The requested
885  * amount of data is then read from the tape device and written to the
886  * data connection.
887  *
888  * Parameters:
889  *   connection (input) - connection handle.
890  *   body       (input) - request message body.
891  *
892  * Returns:
893  *   void
894  */
895 void
896 ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
897 {
898 	ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
899 	ndmp_mover_read_reply reply;
900 	ndmpd_session_t *session = ndmp_get_client_data(connection);
901 	int err;
902 
903 	(void) memset((void*)&reply, 0, sizeof (reply));
904 
905 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
906 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
907 		reply.error = NDMP_ILLEGAL_STATE_ERR;
908 		NDMP_LOG(LOG_DEBUG, "Invalid state");
909 	} else if (session->ns_mover.md_bytes_left_to_read != 0) {
910 		reply.error = NDMP_READ_IN_PROGRESS_ERR;
911 		NDMP_LOG(LOG_DEBUG, "In progress");
912 	} else if (session->ns_tape.td_fd == -1) {
913 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
914 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
915 	} else if (quad_to_long_long(request->length) == 0 ||
916 	    (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
917 	    quad_to_long_long(request->offset) != 0)) {
918 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
919 		NDMP_LOG(LOG_DEBUG, "Illegal args");
920 	} else {
921 		reply.error = NDMP_NO_ERR;
922 	}
923 
924 	ndmp_send_reply(connection, (void *) &reply,
925 	    "sending ndmp_mover_read_reply");
926 	if (reply.error != NDMP_NO_ERR)
927 		return;
928 
929 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
930 	    quad_to_long_long(request->length));
931 	if (err < 0) {
932 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
933 		return;
934 	}
935 
936 	/*
937 	 * Just return if we are waiting for the DMA to complete the seek.
938 	 */
939 	if (err == 1)
940 		return;
941 
942 	/*
943 	 * Setup a handler function that will be called when
944 	 * data can be written to the data connection without blocking.
945 	 */
946 	if (ndmpd_add_file_handler(session, (void*)session,
947 	    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE, HC_MOVER,
948 	    mover_data_write_v3) < 0) {
949 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
950 		return;
951 	}
952 }
953 
954 
955 /*
956  * ndmpd_mover_set_record_size_v3
957  *
958  * This handler handles mover_set_record_size requests.
959  *
960  * Parameters:
961  *   connection (input) - connection handle.
962  *   body       (input) - request message body.
963  *
964  * Returns:
965  *   void
966  */
967 void
968 ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
969 {
970 	ndmp_mover_set_record_size_request *request;
971 	ndmp_mover_set_record_size_reply reply;
972 	ndmpd_session_t *session = ndmp_get_client_data(connection);
973 	char *cp;
974 
975 	request = (ndmp_mover_set_record_size_request *) body;
976 
977 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
978 		reply.error = NDMP_ILLEGAL_STATE_ERR;
979 		NDMP_LOG(LOG_DEBUG, "Invalid mover state %d",
980 		    session->ns_mover.md_state);
981 	} else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
982 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
983 		NDMP_LOG(LOG_DEBUG,
984 		    "Invalid argument %d, should be > 0 and <= %d",
985 		    request->len, ndmp_max_mover_recsize);
986 	} else if (request->len == session->ns_mover.md_record_size)
987 		reply.error = NDMP_NO_ERR;
988 	else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
989 		reply.error = NDMP_NO_MEM_ERR;
990 	} else {
991 		reply.error = NDMP_NO_ERR;
992 		session->ns_mover.md_buf = cp;
993 		session->ns_mover.md_record_size = request->len;
994 		session->ns_mover.md_window_offset = 0;
995 		session->ns_mover.md_window_length = 0;
996 	}
997 
998 	ndmp_send_reply(connection, (void *) &reply,
999 	    "sending mover_set_record_size reply");
1000 }
1001 
1002 
1003 /*
1004  * ndmpd_mover_connect_v3
1005  *   Request handler. Connects the mover to either a local
1006  *   or remote data server.
1007  *
1008  * Parameters:
1009  *   connection (input) - connection handle.
1010  *   body       (input) - request message body.
1011  *
1012  * Returns:
1013  *   void
1014  */
1015 void
1016 ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
1017 {
1018 	ndmp_mover_connect_request_v3 *request;
1019 	ndmp_mover_connect_reply_v3 reply;
1020 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1021 
1022 	request = (ndmp_mover_connect_request_v3*)body;
1023 
1024 	(void) memset((void*)&reply, 0, sizeof (reply));
1025 
1026 	if (request->mode != NDMP_MOVER_MODE_READ &&
1027 	    request->mode != NDMP_MOVER_MODE_WRITE) {
1028 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1029 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1030 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1031 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1032 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1033 		    request->addr.addr_type);
1034 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1035 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1036 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1037 		    session->ns_mover.md_state);
1038 	} else if (session->ns_tape.td_fd == -1) {
1039 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1040 		NDMP_LOG(LOG_DEBUG, "No tape device open");
1041 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1042 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1043 		reply.error = NDMP_WRITE_PROTECT_ERR;
1044 		NDMP_LOG(LOG_ERR, "Write protected device.");
1045 	} else
1046 		reply.error = NDMP_NO_ERR;
1047 
1048 	if (reply.error != NDMP_NO_ERR) {
1049 		ndmp_send_reply(connection, (void *) &reply,
1050 		    "sending ndmp_mover_connect reply");
1051 		return;
1052 	}
1053 
1054 	switch (request->addr.addr_type) {
1055 	case NDMP_ADDR_LOCAL:
1056 		/*
1057 		 * Verify that the data server is listening for a
1058 		 * local connection.
1059 		 */
1060 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1061 		    session->ns_data.dd_listen_sock != -1) {
1062 			NDMP_LOG(LOG_DEBUG,
1063 			    "Data server is not in local listen state");
1064 			reply.error = NDMP_ILLEGAL_STATE_ERR;
1065 		} else
1066 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1067 		break;
1068 
1069 	case NDMP_ADDR_TCP:
1070 		reply.error = mover_connect_sock_v3(session, request->mode,
1071 		    request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
1072 		break;
1073 
1074 	default:
1075 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1076 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1077 		    request->addr.addr_type);
1078 	}
1079 
1080 	if (reply.error == NDMP_NO_ERR) {
1081 		session->ns_mover.md_data_addr.addr_type =
1082 		    request->addr.addr_type;
1083 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1084 		session->ns_mover.md_mode = request->mode;
1085 	}
1086 
1087 	ndmp_send_reply(connection, (void *) &reply,
1088 	    "sending ndmp_mover_connect reply");
1089 }
1090 
1091 
1092 /*
1093  * ************************************************************************
1094  * NDMP V4 HANDLERS
1095  * ************************************************************************
1096  */
1097 
1098 /*
1099  * ndmpd_mover_get_state_v4
1100  *
1101  * This handler handles the ndmp_mover_get_state_request.
1102  * Status information for the mover state machine is returned.
1103  *
1104  * Parameters:
1105  *   connection (input) - connection handle.
1106  *   body       (input) - request message body.
1107  *
1108  * Returns:
1109  *   void
1110  */
1111 /*ARGSUSED*/
1112 void
1113 ndmpd_mover_get_state_v4(ndmp_connection_t *connection, void *body)
1114 {
1115 	ndmp_mover_get_state_reply_v4 reply;
1116 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1117 
1118 	(void) memset((void*)&reply, 0, sizeof (reply));
1119 
1120 	reply.error = NDMP_NO_ERR;
1121 	reply.state = session->ns_mover.md_state;
1122 	reply.mode = session->ns_mover.md_mode;
1123 	reply.pause_reason = session->ns_mover.md_pause_reason;
1124 	reply.halt_reason = session->ns_mover.md_halt_reason;
1125 	reply.record_size = session->ns_mover.md_record_size;
1126 	reply.record_num = session->ns_mover.md_record_num;
1127 	reply.bytes_moved =
1128 	    long_long_to_quad(session->ns_mover.md_data_written);
1129 	reply.seek_position =
1130 	    long_long_to_quad(session->ns_mover.md_seek_position);
1131 	reply.bytes_left_to_read =
1132 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
1133 	reply.window_offset =
1134 	    long_long_to_quad(session->ns_mover.md_window_offset);
1135 	reply.window_length =
1136 	    long_long_to_quad(session->ns_mover.md_window_length);
1137 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
1138 		ndmp_copy_addr_v4(&reply.data_connection_addr,
1139 		    &session->ns_mover.md_data_addr_v4);
1140 
1141 	ndmp_send_reply(connection, (void *) &reply,
1142 	    "sending ndmp_mover_get_state reply");
1143 	free(reply.data_connection_addr.tcp_addr_v4);
1144 }
1145 
1146 
1147 /*
1148  * ndmpd_mover_listen_v4
1149  *
1150  * This handler handles ndmp_mover_listen_requests.
1151  * A TCP/IP socket is created that is used to listen for
1152  * and accept data connections initiated by a remote
1153  * data server.
1154  *
1155  * Parameters:
1156  *   connection (input) - connection handle.
1157  *   body       (input) - request message body.
1158  *
1159  * Returns:
1160  *   void
1161  */
1162 void
1163 ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
1164 {
1165 	ndmp_mover_listen_request_v4 *request;
1166 
1167 	ndmp_mover_listen_reply_v4 reply;
1168 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1169 	ulong_t addr;
1170 	ushort_t port;
1171 
1172 	request = (ndmp_mover_listen_request_v4 *)body;
1173 
1174 	(void) memset((void*)&reply, 0, sizeof (reply));
1175 	reply.error = NDMP_NO_ERR;
1176 
1177 	if (request->mode != NDMP_MOVER_MODE_READ &&
1178 	    request->mode != NDMP_MOVER_MODE_WRITE) {
1179 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1180 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1181 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
1182 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1183 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1184 		    request->addr_type);
1185 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1186 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1187 		NDMP_LOG(LOG_DEBUG,
1188 		    "Invalid mover state to process listen request");
1189 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1190 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1191 		NDMP_LOG(LOG_DEBUG,
1192 		    "Invalid data state to process listen request");
1193 	} else if (session->ns_tape.td_fd == -1) {
1194 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1195 		NDMP_LOG(LOG_DEBUG, "No tape device open");
1196 	} else if (session->ns_mover.md_record_size == 0) {
1197 		reply.error = NDMP_PRECONDITION_ERR;
1198 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1199 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1200 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1201 		reply.error = NDMP_PERMISSION_ERR;
1202 		NDMP_LOG(LOG_ERR, "Write protected device.");
1203 	}
1204 
1205 	if (reply.error != NDMP_NO_ERR) {
1206 		ndmp_send_reply(connection, (void *) &reply,
1207 		    "error sending ndmp_mover_listen reply");
1208 		return;
1209 	}
1210 
1211 	switch (request->addr_type) {
1212 	case NDMP_ADDR_LOCAL:
1213 		reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
1214 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
1215 		reply.error = NDMP_NO_ERR;
1216 		break;
1217 	case NDMP_ADDR_TCP:
1218 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
1219 			reply.error = NDMP_IO_ERR;
1220 			break;
1221 		}
1222 		reply.error = NDMP_NO_ERR;
1223 
1224 		session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1225 		session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
1226 		session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
1227 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1228 
1229 		session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
1230 		session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1231 
1232 		ndmp_copy_addr_v4(&reply.connect_addr,
1233 		    &session->ns_mover.md_data_addr_v4);
1234 
1235 		/* For compatibility with V3 */
1236 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
1237 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
1238 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
1239 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
1240 		    session->ns_mover.md_listen_sock);
1241 		break;
1242 	default:
1243 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1244 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
1245 		    request->addr_type);
1246 	}
1247 
1248 	if (reply.error == NDMP_NO_ERR) {
1249 		session->ns_mover.md_mode = request->mode;
1250 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
1251 	}
1252 
1253 	ndmp_send_reply(connection, (void *) &reply,
1254 	    "error sending ndmp_mover_listen reply");
1255 	free(reply.connect_addr.tcp_addr_v4);
1256 }
1257 
1258 /*
1259  * ndmpd_mover_connect_v4
1260  *   Request handler. Connects the mover to either a local
1261  *   or remote data server.
1262  *
1263  * Parameters:
1264  *   connection (input) - connection handle.
1265  *   body       (input) - request message body.
1266  *
1267  * Returns:
1268  *   void
1269  */
1270 void
1271 ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
1272 {
1273 	ndmp_mover_connect_request_v4 *request;
1274 	ndmp_mover_connect_reply_v4 reply;
1275 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1276 
1277 	request = (ndmp_mover_connect_request_v4 *)body;
1278 	(void) memset((void*)&reply, 0, sizeof (reply));
1279 
1280 	if (request->mode != NDMP_MOVER_MODE_READ &&
1281 	    request->mode != NDMP_MOVER_MODE_WRITE) {
1282 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1283 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1284 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1285 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1286 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1287 		    request->addr.addr_type);
1288 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1289 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1290 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1291 		    session->ns_mover.md_state);
1292 	} else if (session->ns_tape.td_fd == -1) {
1293 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1294 		NDMP_LOG(LOG_DEBUG, "No tape device open");
1295 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1296 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1297 		reply.error = NDMP_PERMISSION_ERR;
1298 		NDMP_LOG(LOG_ERR, "Write protected device.");
1299 	} else if (session->ns_mover.md_record_size == 0) {
1300 		reply.error = NDMP_PRECONDITION_ERR;
1301 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1302 	} else
1303 		reply.error = NDMP_NO_ERR;
1304 
1305 	if (reply.error != NDMP_NO_ERR) {
1306 		ndmp_send_reply(connection, (void *) &reply,
1307 		    "sending ndmp_mover_connect reply");
1308 		return;
1309 	}
1310 
1311 	switch (request->addr.addr_type) {
1312 	case NDMP_ADDR_LOCAL:
1313 		/*
1314 		 * Verify that the data server is listening for a
1315 		 * local connection.
1316 		 */
1317 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1318 		    session->ns_data.dd_listen_sock != -1) {
1319 			NDMP_LOG(LOG_DEBUG,
1320 			    "Data server is not in local listen state");
1321 			reply.error = NDMP_ILLEGAL_STATE_ERR;
1322 		} else
1323 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1324 		break;
1325 
1326 	case NDMP_ADDR_TCP:
1327 		reply.error = mover_connect_sock_v3(session, request->mode,
1328 		    request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
1329 		break;
1330 
1331 	default:
1332 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1333 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1334 		    request->addr.addr_type);
1335 	}
1336 
1337 	if (reply.error == NDMP_NO_ERR) {
1338 		session->ns_mover.md_data_addr.addr_type =
1339 		    request->addr.addr_type;
1340 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1341 		session->ns_mover.md_mode = request->mode;
1342 	}
1343 
1344 	ndmp_send_reply(connection, (void *) &reply,
1345 	    "sending ndmp_mover_connect reply");
1346 }
1347 
1348 
1349 
1350 /*
1351  * ************************************************************************
1352  * LOCALS
1353  * ************************************************************************
1354  */
1355 
1356 /*
1357  * ndmpd_local_write
1358  *
1359  * Writes data to the mover.
1360  * Buffers and write data to the tape device.
1361  * A full tape record is buffered before being written.
1362  *
1363  * Parameters:
1364  *   session    (input) - session pointer.
1365  *   data       (input) - data to be written.
1366  *   length     (input) - data length.
1367  *
1368  * Returns:
1369  *   0 - data successfully written.
1370  *  -1 - error.
1371  */
1372 int
1373 ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
1374 {
1375 	ulong_t count = 0;
1376 	ssize_t n;
1377 	ulong_t len;
1378 
1379 	/*
1380 	 * A length of 0 indicates that any buffered data should be
1381 	 * flushed to tape.
1382 	 */
1383 	if (length == 0) {
1384 		if (session->ns_mover.md_w_index == 0)
1385 			return (0);
1386 
1387 		(void) memset(
1388 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1389 		    0, session->ns_mover.md_record_size -
1390 		    session->ns_mover.md_w_index);
1391 
1392 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
1393 		    session->ns_mover.md_record_size);
1394 		if (n <= 0) {
1395 			ndmpd_mover_error(session,
1396 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1397 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
1398 			return (-1);
1399 		}
1400 		session->ns_mover.md_position += n;
1401 		session->ns_mover.md_data_written +=
1402 		    session->ns_mover.md_w_index;
1403 		session->ns_mover.md_record_num++;
1404 		session->ns_mover.md_w_index = 0;
1405 		return (0);
1406 	}
1407 	/* Break the data into records. */
1408 	while (count < length) {
1409 		/*
1410 		 * Determine if data needs to be buffered or
1411 		 * can be written directly from user supplied location.
1412 		 * We can fast path the write if there is no pending
1413 		 * buffered data and there is at least a full record's worth
1414 		 * of data to be written.
1415 		 */
1416 		if (session->ns_mover.md_w_index == 0 &&
1417 		    length - count >= session->ns_mover.md_record_size) {
1418 			n = mover_tape_write_v3(session, &data[count],
1419 			    session->ns_mover.md_record_size);
1420 			if (n <= 0) {
1421 				ndmpd_mover_error(session,
1422 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1423 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1424 				return (-1);
1425 			}
1426 			session->ns_mover.md_position += n;
1427 			session->ns_mover.md_data_written += n;
1428 			session->ns_mover.md_record_num++;
1429 			count += n;
1430 			continue;
1431 		}
1432 		/* Buffer the data */
1433 		len = length - count;
1434 		if (len > session->ns_mover.md_record_size -
1435 		    session->ns_mover.md_w_index)
1436 			len = session->ns_mover.md_record_size -
1437 			    session->ns_mover.md_w_index;
1438 
1439 		(void) memcpy(
1440 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1441 		    &data[count], len);
1442 		session->ns_mover.md_w_index += len;
1443 		count += len;
1444 
1445 		/* Write the buffer if its full */
1446 		if (session->ns_mover.md_w_index ==
1447 		    session->ns_mover.md_record_size) {
1448 			n = mover_tape_write_v3(session,
1449 			    session->ns_mover.md_buf,
1450 			    session->ns_mover.md_record_size);
1451 			if (n <= 0) {
1452 				ndmpd_mover_error(session,
1453 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1454 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1455 				return (-1);
1456 			}
1457 			session->ns_mover.md_position += n;
1458 			session->ns_mover.md_data_written += n;
1459 			session->ns_mover.md_record_num++;
1460 			session->ns_mover.md_w_index = 0;
1461 		}
1462 	}
1463 
1464 	return (0);
1465 }
1466 
1467 
1468 /*
1469  * ndmpd_remote_write
1470  *
1471  * Writes data to the remote mover.
1472  *
1473  * Parameters:
1474  *   session    (input) - session pointer.
1475  *   data       (input) - data to be written.
1476  *   length     (input) - data length.
1477  *
1478  * Returns:
1479  *   0 - data successfully written.
1480  *  -1 - error.
1481  */
1482 int
1483 ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
1484 {
1485 	ssize_t n;
1486 	ulong_t count = 0;
1487 
1488 	while (count < length) {
1489 		if (session->ns_eof == TRUE ||
1490 		    session->ns_data.dd_abort == TRUE)
1491 			return (-1);
1492 
1493 		if ((n = write(session->ns_data.dd_sock, &data[count],
1494 		    length - count)) < 0) {
1495 			NDMP_LOG(LOG_ERR, "Socket write error: %m.");
1496 			return (-1);
1497 		}
1498 		count += n;
1499 	}
1500 
1501 	return (0);
1502 }
1503 
1504 /*
1505  * ndmpd_local_read
1506  *
1507  * Reads data from the local tape device.
1508  * Full tape records are read and buffered.
1509  *
1510  * Parameters:
1511  *   session (input) - session pointer.
1512  *   data    (input) - location to store data.
1513  *   length  (input) - data length.
1514  *
1515  * Returns:
1516  *   0 - data successfully read.
1517  *  -1 - error.
1518  *   1 - session terminated or operation aborted.
1519  */
1520 int
1521 ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
1522 {
1523 	ulong_t count = 0;
1524 	ssize_t n;
1525 	ulong_t len;
1526 	ndmp_notify_mover_paused_request pause_request;
1527 
1528 	/*
1529 	 * Automatically increase the seek window if necessary.
1530 	 * This is needed in the event the module attempts to read
1531 	 * past a seek window set via a prior call to ndmpd_seek() or
1532 	 * the module has not issued a seek. If no seek was issued then
1533 	 * pretend that a seek was issued to read the entire tape.
1534 	 */
1535 	if (length > session->ns_mover.md_bytes_left_to_read) {
1536 		/* ndmpd_seek() never called? */
1537 		if (session->ns_data.dd_read_length == 0) {
1538 			session->ns_mover.md_bytes_left_to_read = ~0LL;
1539 			session->ns_data.dd_read_offset = 0LL;
1540 			session->ns_data.dd_read_length = ~0LL;
1541 		} else {
1542 			session->ns_mover.md_bytes_left_to_read = length;
1543 			session->ns_data.dd_read_offset =
1544 			    session->ns_mover.md_position;
1545 			session->ns_data.dd_read_length = length;
1546 		}
1547 	}
1548 	/*
1549 	 * Read as many records as necessary to satisfy the request.
1550 	 */
1551 	while (count < length) {
1552 		/*
1553 		 * If the end of the mover window has been reached,
1554 		 * then notify the client that a new data window is needed.
1555 		 */
1556 		if (session->ns_mover.md_position >=
1557 		    session->ns_mover.md_window_offset +
1558 		    session->ns_mover.md_window_length) {
1559 
1560 			session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
1561 			session->ns_mover.md_pause_reason =
1562 			    NDMP_MOVER_PAUSE_SEEK;
1563 			pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
1564 			pause_request.seek_position =
1565 			    long_long_to_quad(session->ns_mover.md_position);
1566 
1567 			if (ndmp_send_request(session->ns_connection,
1568 			    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
1569 			    (void *) &pause_request, 0) < 0) {
1570 				NDMP_LOG(LOG_DEBUG,
1571 				    "Sending notify_mover_paused request");
1572 				ndmpd_mover_error(session,
1573 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
1574 				return (-1);
1575 			}
1576 			/*
1577 			 * Wait until the state is changed by
1578 			 * an abort or continue request.
1579 			 */
1580 			nlp_ref_nw(session);
1581 			for (; ; ) {
1582 				nlp_wait_nw(session);
1583 
1584 				if (session->ns_eof == TRUE) {
1585 					nlp_unref_nw(session);
1586 					return (1);
1587 				}
1588 
1589 				switch (session->ns_mover.md_state) {
1590 				case NDMP_MOVER_STATE_ACTIVE:
1591 					break;
1592 
1593 				case NDMP_MOVER_STATE_PAUSED:
1594 					continue;
1595 
1596 				default:
1597 					nlp_unref_nw(session);
1598 					return (-1);
1599 				}
1600 			}
1601 		}
1602 		len = length - count;
1603 
1604 		/*
1605 		 * Prevent reading past the end of the window.
1606 		 */
1607 		if (len >
1608 		    session->ns_mover.md_window_offset +
1609 		    session->ns_mover.md_window_length -
1610 		    session->ns_mover.md_position)
1611 			len = session->ns_mover.md_window_offset +
1612 			    session->ns_mover.md_window_length -
1613 			    session->ns_mover.md_position;
1614 
1615 		/*
1616 		 * Copy from the data buffer first.
1617 		 */
1618 		if (session->ns_mover.md_w_index -
1619 		    session->ns_mover.md_r_index != 0) {
1620 			/*
1621 			 * Limit the copy to the amount of data in the buffer.
1622 			 */
1623 			if (len > session->ns_mover.md_w_index -
1624 			    session->ns_mover.md_r_index)
1625 				len = session->ns_mover.md_w_index
1626 				    - session->ns_mover.md_r_index;
1627 
1628 			(void) memcpy((void *) &data[count],
1629 			    &session->ns_mover.md_buf[session->
1630 			    ns_mover.md_r_index], len);
1631 			count += len;
1632 			session->ns_mover.md_r_index += len;
1633 			session->ns_mover.md_bytes_left_to_read -= len;
1634 			session->ns_mover.md_position += len;
1635 			continue;
1636 		}
1637 		/*
1638 		 * Determine if data needs to be buffered or
1639 		 * can be read directly to user supplied location.
1640 		 * We can fast path the read if at least a full record
1641 		 * needs to be read and there is no seek pending.
1642 		 * This is done to eliminate a buffer copy.
1643 		 */
1644 		if (len >= session->ns_mover.md_record_size &&
1645 		    session->ns_mover.md_position >=
1646 		    session->ns_mover.md_seek_position) {
1647 			n = tape_read(session, &data[count]);
1648 			if (n <= 0) {
1649 				if (n == TAPE_NO_WRITER_ERR)
1650 					return (1);
1651 
1652 				ndmpd_mover_error(session,
1653 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1654 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1655 				return (n == 0) ? (1) : (-1);
1656 			}
1657 			count += n;
1658 			session->ns_mover.md_bytes_left_to_read -= n;
1659 			session->ns_mover.md_position += n;
1660 			continue;
1661 		}
1662 		/* Read the next record into the buffer. */
1663 		n = tape_read(session, session->ns_mover.md_buf);
1664 		if (n <= 0) {
1665 			if (n == TAPE_NO_WRITER_ERR)
1666 				return (1);
1667 
1668 			ndmpd_mover_error(session,
1669 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1670 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
1671 			return (n == 0) ? (1) : (-1);
1672 		}
1673 		session->ns_mover.md_w_index = n;
1674 		session->ns_mover.md_r_index = 0;
1675 
1676 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
1677 
1678 		/*
1679 		 * Discard data if the current data stream position is
1680 		 * prior to the seek position. This is necessary if a seek
1681 		 * request set the seek pointer to a position that is not a
1682 		 * record boundary. The seek request handler can only position
1683 		 * to the start of a record.
1684 		 */
1685 		if (session->ns_mover.md_position <
1686 		    session->ns_mover.md_seek_position) {
1687 			session->ns_mover.md_r_index =
1688 			    session->ns_mover.md_seek_position -
1689 			    session->ns_mover.md_position;
1690 			session->ns_mover.md_position =
1691 			    session->ns_mover.md_seek_position;
1692 		}
1693 	}
1694 
1695 	return (0);
1696 }
1697 
1698 
1699 /*
1700  * ndmpd_remote_read
1701  *
1702  * Reads data from the remote mover.
1703  *
1704  * Parameters:
1705  *   session (input) - session pointer.
1706  *   data    (input) - data to be written.
1707  *   length  (input) - data length.
1708  *
1709  * Returns:
1710  *   0 - data successfully read.
1711  *  -1 - error.
1712  *   1 - session terminated or operation aborted.
1713  */
1714 int
1715 ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
1716 {
1717 	ulong_t count = 0;
1718 	ssize_t n;
1719 	ulong_t len;
1720 	ndmp_notify_data_read_request request;
1721 
1722 	while (count < length) {
1723 		len = length - count;
1724 
1725 		/*
1726 		 * If the end of the seek window has been reached then
1727 		 * send an ndmp_read request to the client.
1728 		 * The NDMP client will then send a mover_data_read request to
1729 		 * the remote mover and the mover will send more data.
1730 		 * This condition can occur if the module attempts to read past
1731 		 * a seek window set via a prior call to ndmpd_seek() or
1732 		 * the module has not issued a seek. If no seek was issued then
1733 		 * pretend that a seek was issued to read the entire tape.
1734 		 */
1735 		if (session->ns_mover.md_bytes_left_to_read == 0) {
1736 			/* ndmpd_seek() never called? */
1737 			if (session->ns_data.dd_read_length == 0) {
1738 				session->ns_mover.md_bytes_left_to_read = ~0LL;
1739 				session->ns_data.dd_read_offset = 0LL;
1740 				session->ns_data.dd_read_length = ~0LL;
1741 			} else {
1742 				session->ns_mover.md_bytes_left_to_read = len;
1743 				session->ns_data.dd_read_offset =
1744 				    session->ns_mover.md_position;
1745 				session->ns_data.dd_read_length = len;
1746 			}
1747 
1748 			request.offset =
1749 			    long_long_to_quad(session->ns_data.dd_read_offset);
1750 			request.length =
1751 			    long_long_to_quad(session->ns_data.dd_read_length);
1752 
1753 			if (ndmp_send_request_lock(session->ns_connection,
1754 			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1755 			    (void *) &request, 0) < 0) {
1756 				NDMP_LOG(LOG_DEBUG,
1757 				    "Sending notify_data_read request");
1758 				return (-1);
1759 			}
1760 		}
1761 		if (session->ns_eof == TRUE ||
1762 		    session->ns_data.dd_abort == TRUE)
1763 			return (1);
1764 
1765 		/*
1766 		 * If the module called ndmpd_seek() prior to reading all of the
1767 		 * data that the remote mover was requested to send, then the
1768 		 * excess data from the seek has to be discardd.
1769 		 */
1770 		if (session->ns_mover.md_discard_length != 0) {
1771 			n = discard_data(session,
1772 			    (ulong_t)session->ns_mover.md_discard_length);
1773 			if (n < 0)
1774 				return (-1);
1775 			session->ns_mover.md_discard_length -= n;
1776 			continue;
1777 		}
1778 		/*
1779 		 * Don't attempt to read more data than the remote is sending.
1780 		 */
1781 		if (len > session->ns_mover.md_bytes_left_to_read)
1782 			len = session->ns_mover.md_bytes_left_to_read;
1783 
1784 		NDMP_LOG(LOG_DEBUG, "len: %u", len);
1785 
1786 		if ((n = read(session->ns_data.dd_sock, &data[count],
1787 		    len)) < 0) {
1788 			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1789 			return (-1);
1790 		}
1791 		/* read returns 0 if the connection was closed */
1792 		if (n == 0)
1793 			return (-1);
1794 
1795 		count += n;
1796 		session->ns_mover.md_bytes_left_to_read -= n;
1797 		session->ns_mover.md_position += n;
1798 	}
1799 
1800 	return (0);
1801 }
1802 
1803 /* *** ndmpd internal functions ***************************************** */
1804 
1805 /*
1806  * ndmpd_mover_init
1807  *
1808  * Initialize mover specific session variables.
1809  * Don't initialize variables such as record_size that need to
1810  * persist across data operations. A client may open a connection and
1811  * do multiple backups after setting the record_size.
1812  *
1813  * Parameters:
1814  *   session (input) - session pointer.
1815  *
1816  * Returns:
1817  *   0 - success.
1818  *  -1 - error.
1819  */
1820 int
1821 ndmpd_mover_init(ndmpd_session_t *session)
1822 {
1823 	session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
1824 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
1825 	session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
1826 	session->ns_mover.md_data_written = 0LL;
1827 	session->ns_mover.md_seek_position = 0LL;
1828 	session->ns_mover.md_bytes_left_to_read = 0LL;
1829 	session->ns_mover.md_window_offset = 0LL;
1830 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
1831 	session->ns_mover.md_position = 0LL;
1832 	session->ns_mover.md_discard_length = 0;
1833 	session->ns_mover.md_record_num = 0;
1834 	session->ns_mover.md_record_size = 0;
1835 	session->ns_mover.md_listen_sock = -1;
1836 	session->ns_mover.md_pre_cond = FALSE;
1837 	session->ns_mover.md_sock = -1;
1838 	session->ns_mover.md_r_index = 0;
1839 	session->ns_mover.md_w_index = 0;
1840 	session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
1841 	if (!session->ns_mover.md_buf)
1842 		return (-1);
1843 
1844 	if (ndmp_get_version(session->ns_connection) == NDMPV3) {
1845 		session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
1846 		(void) memset(&session->ns_mover.md_data_addr, 0,
1847 		    sizeof (ndmp_addr_v3));
1848 	}
1849 	return (0);
1850 }
1851 
1852 
1853 /*
1854  * ndmpd_mover_shut_down
1855  *
1856  * Shutdown the mover. It closes all the sockets.
1857  *
1858  * Parameters:
1859  *   session (input) - session pointer.
1860  *
1861  * Returns:
1862  *   void
1863  */
1864 void
1865 ndmpd_mover_shut_down(ndmpd_session_t *session)
1866 {
1867 	if (session->ns_mover.md_listen_sock != -1) {
1868 		NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
1869 		    session->ns_mover.md_listen_sock);
1870 		(void) ndmpd_remove_file_handler(session,
1871 		    session->ns_mover.md_listen_sock);
1872 		(void) close(session->ns_mover.md_listen_sock);
1873 		session->ns_mover.md_listen_sock = -1;
1874 	}
1875 	if (session->ns_mover.md_sock != -1) {
1876 		NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
1877 		    session->ns_mover.md_sock);
1878 		(void) ndmpd_remove_file_handler(session,
1879 		    session->ns_mover.md_sock);
1880 		(void) close(session->ns_mover.md_sock);
1881 		session->ns_mover.md_sock = -1;
1882 	}
1883 }
1884 
1885 
1886 /*
1887  * ndmpd_mover_cleanup
1888  *
1889  * Parameters:
1890  *   session (input) - session pointer.
1891  *
1892  * Returns:
1893  *   void
1894  */
1895 void
1896 ndmpd_mover_cleanup(ndmpd_session_t *session)
1897 {
1898 	NDMP_FREE(session->ns_mover.md_buf);
1899 }
1900 
1901 
1902 /*
1903  * ndmpd_mover_connect
1904  *   Create a connection to the specified mover.
1905  *
1906  * Parameters:
1907  *   session (input) - session pointer
1908  *
1909  * Returns:
1910  *   error code.
1911  */
1912 ndmp_error
1913 ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
1914 {
1915 	ndmp_mover_addr *mover = &session->ns_data.dd_mover;
1916 	struct sockaddr_in sin;
1917 	int sock = -1;
1918 	int flag = 1;
1919 
1920 	if (mover->addr_type == NDMP_ADDR_TCP) {
1921 		if (mover->ndmp_mover_addr_u.addr.ip_addr) {
1922 			(void) memset((void *) &sin, 0, sizeof (sin));
1923 			sin.sin_family = AF_INET;
1924 			sin.sin_addr.s_addr =
1925 			    htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
1926 			sin.sin_port =
1927 			    htons(mover->ndmp_mover_addr_u.addr.port);
1928 
1929 			/*
1930 			 * If the address type is TCP but both the address and
1931 			 * the port number are zero, we have to use a different
1932 			 * socket than the mover socket. This can happen when
1933 			 * using NDMP disk to disk copy (AKA D2D copy).
1934 			 * The NDMPCopy client will send a zero address to
1935 			 * direct the server to use the mover socket as the
1936 			 * data socket to receive the recovery data.
1937 			 */
1938 			if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
1939 				session->ns_data.dd_sock =
1940 				    session->ns_mover.md_sock;
1941 				return (NDMP_NO_ERR);
1942 			}
1943 
1944 			NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
1945 			    mover->ndmp_mover_addr_u.addr.ip_addr,
1946 			    (ulong_t)sin.sin_port);
1947 
1948 			if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1949 				NDMP_LOG(LOG_DEBUG, "Socket error: %m");
1950 				return (NDMP_IO_ERR);
1951 			}
1952 			if (connect(sock, (struct sockaddr *)&sin,
1953 			    sizeof (sin)) < 0) {
1954 				NDMP_LOG(LOG_DEBUG, "Connect error: %m");
1955 				(void) close(sock);
1956 				return (NDMP_IO_ERR);
1957 			}
1958 
1959 			if (ndmp_sbs > 0)
1960 				ndmp_set_socket_snd_buf(sock,
1961 				    ndmp_sbs * KILOBYTE);
1962 			if (ndmp_rbs > 0)
1963 				ndmp_set_socket_rcv_buf(sock,
1964 				    ndmp_rbs * KILOBYTE);
1965 
1966 			ndmp_set_socket_nodelay(sock);
1967 			(void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag,
1968 			    sizeof (flag));
1969 		} else {
1970 			if ((session->ns_mover.md_state !=
1971 			    NDMP_MOVER_STATE_ACTIVE) ||
1972 			    (session->ns_mover.md_sock == -1)) {
1973 
1974 				NDMP_LOG(LOG_DEBUG,
1975 				    "Not in active  state mover"
1976 				    "  state = %d or Invalid mover sock=%d",
1977 				    session->ns_mover.md_state,
1978 				    session->ns_mover.md_sock);
1979 				return (NDMP_ILLEGAL_STATE_ERR);
1980 			}
1981 
1982 			sock = session->ns_mover.md_sock;
1983 			NDMP_LOG(LOG_DEBUG,
1984 			    "session: 0x%x setting data sock fd: %d to be"
1985 			    " same as listen_sock", session, sock);
1986 		}
1987 
1988 		NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
1989 
1990 		session->ns_data.dd_sock = sock;
1991 
1992 		NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
1993 
1994 		return (NDMP_NO_ERR);
1995 	}
1996 	/* Local mover connection. */
1997 
1998 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
1999 		NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
2000 		return (NDMP_ILLEGAL_STATE_ERR);
2001 	}
2002 	if (session->ns_tape.td_fd == -1) {
2003 		NDMP_LOG(LOG_DEBUG, "Tape device not open");
2004 		return (NDMP_DEV_NOT_OPEN_ERR);
2005 	}
2006 	if (mover_mode == NDMP_MOVER_MODE_READ &&
2007 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
2008 		NDMP_LOG(LOG_ERR, "Write protected device.");
2009 		return (NDMP_WRITE_PROTECT_ERR);
2010 	}
2011 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2012 	session->ns_mover.md_mode = mover_mode;
2013 
2014 	return (NDMP_NO_ERR);
2015 }
2016 
2017 
2018 
2019 /*
2020  * ndmpd_mover_seek
2021  *
2022  * Seek to the requested data stream position.
2023  * If the requested offset is outside of the current window,
2024  * the mover is paused and a notify_mover_paused request is sent
2025  * notifying the client that a seek is required.
2026  * If the requested offest is within the window but not within the
2027  * current record, then the tape is positioned to the record containing
2028  * the requested offest.
2029  * The requested amount of data is then read from the tape device and
2030  * written to the data connection.
2031  *
2032  * Parameters:
2033  *   session (input) - session pointer.
2034  *   offset  (input) - data stream position to seek to.
2035  *   length  (input) - amount of data that will be read.
2036  *
2037  * Returns:
2038  *   1 - seek pending completion by the NDMP client.
2039  *   0 - seek successfully completed.
2040  *  -1 - error.
2041  */
2042 int
2043 ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
2044     u_longlong_t length)
2045 {
2046 	int ctlcmd;
2047 	int ctlcnt;
2048 	u_longlong_t tape_position;
2049 	u_longlong_t buf_position;
2050 	ndmp_notify_mover_paused_request pause_request;
2051 
2052 	session->ns_mover.md_seek_position = offset;
2053 	session->ns_mover.md_bytes_left_to_read = length;
2054 
2055 	/*
2056 	 * If the requested position is outside of the window,
2057 	 * notify the client that a seek is required.
2058 	 */
2059 	if (session->ns_mover.md_seek_position <
2060 	    session->ns_mover.md_window_offset ||
2061 	    session->ns_mover.md_seek_position >=
2062 	    session->ns_mover.md_window_offset +
2063 	    session->ns_mover.md_window_length) {
2064 		NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
2065 		    session->ns_mover.md_seek_position);
2066 
2067 		session->ns_mover.md_w_index = 0;
2068 		session->ns_mover.md_r_index = 0;
2069 
2070 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2071 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2072 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2073 		pause_request.seek_position = long_long_to_quad(offset);
2074 
2075 		if (ndmp_send_request(session->ns_connection,
2076 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2077 		    (void *) &pause_request, 0) < 0) {
2078 			NDMP_LOG(LOG_DEBUG,
2079 			    "Sending notify_mover_paused request");
2080 			return (-1);
2081 		}
2082 		return (1);
2083 	}
2084 	/*
2085 	 * Determine the data stream position of the first byte in the
2086 	 * data buffer.
2087 	 */
2088 	buf_position = session->ns_mover.md_position -
2089 	    (session->ns_mover.md_position % session->ns_mover.md_record_size);
2090 
2091 	/*
2092 	 * Determine the data stream position of the next byte that
2093 	 * will be read from tape.
2094 	 */
2095 	tape_position = buf_position;
2096 	if (session->ns_mover.md_w_index != 0)
2097 		tape_position += session->ns_mover.md_record_size;
2098 
2099 	/*
2100 	 * Check if requested position is for data that has been read and is
2101 	 * in the buffer.
2102 	 */
2103 	if (offset >= buf_position && offset < tape_position) {
2104 		session->ns_mover.md_position = offset;
2105 		session->ns_mover.md_r_index = session->ns_mover.md_position -
2106 		    buf_position;
2107 
2108 		NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
2109 		    session->ns_mover.md_position,
2110 		    session->ns_mover.md_r_index);
2111 
2112 		return (0);
2113 	}
2114 
2115 	ctlcmd = 0;
2116 	if (tape_position > session->ns_mover.md_seek_position) {
2117 		/* Need to seek backward. */
2118 		ctlcmd = MTBSR;
2119 		ctlcnt = (int)((tape_position - offset - 1)
2120 		    / session->ns_mover.md_record_size) + 1;
2121 		tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
2122 		    session->ns_mover.md_record_size) + 1) *
2123 		    (u_longlong_t)session->ns_mover.md_record_size);
2124 
2125 	} else if (offset >= tape_position + session->ns_mover.md_record_size) {
2126 		/* Need to seek forward. */
2127 		ctlcmd = MTFSR;
2128 		ctlcnt = (int)((offset - tape_position)
2129 		    / session->ns_mover.md_record_size);
2130 		tape_position += ((u_longlong_t)(((offset - tape_position) /
2131 		    session->ns_mover.md_record_size)) *
2132 		    (u_longlong_t)session->ns_mover.md_record_size);
2133 	}
2134 	/* Reposition the tape if necessary. */
2135 	if (ctlcmd) {
2136 		NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
2137 		    ctlcmd, ctlcnt);
2138 		(void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
2139 	}
2140 
2141 	session->ns_mover.md_position = tape_position;
2142 	session->ns_mover.md_r_index = 0;
2143 	session->ns_mover.md_w_index = 0;
2144 
2145 	NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
2146 
2147 	return (0);
2148 }
2149 
2150 
2151 /* ** static functions ************************************************** */
2152 
2153 /*
2154  * create_listen_socket_v2
2155  *
2156  * Creates a socket for listening for accepting data connections.
2157  *
2158  * Parameters:
2159  *   session (input)  - session pointer.
2160  *   addr    (output) - location to store address of socket.
2161  *   port    (output) - location to store port of socket.
2162  *
2163  * Returns:
2164  *   0 - success.
2165  *  -1 - error.
2166  */
2167 static int
2168 create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
2169 {
2170 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
2171 	if (session->ns_mover.md_listen_sock < 0)
2172 		return (-1);
2173 
2174 	/*
2175 	 * Add a file handler for the listen socket.
2176 	 * ndmpd_select will call accept_connection when a
2177 	 * connection is ready to be accepted.
2178 	 */
2179 	if (ndmpd_add_file_handler(session, (void *) session,
2180 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
2181 	    accept_connection) < 0) {
2182 		(void) close(session->ns_mover.md_listen_sock);
2183 		session->ns_mover.md_listen_sock = -1;
2184 		return (-1);
2185 	}
2186 
2187 	NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
2188 	return (0);
2189 }
2190 
2191 
2192 /*
2193  * accept_connection
2194  *
2195  * Accept a data connection from a data server.
2196  * Called by ndmpd_select when a connection is pending on
2197  * the mover listen socket.
2198  *
2199  * Parameters:
2200  *   cookie  (input) - session pointer.
2201  *   fd      (input) - file descriptor.
2202  *   mode    (input) - select mode.
2203  *
2204  * Returns:
2205  *   void.
2206  */
2207 /*ARGSUSED*/
2208 static void
2209 accept_connection(void *cookie, int fd, ulong_t mode)
2210 {
2211 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
2212 	struct sockaddr_in from;
2213 	int from_len;
2214 	int flag = 1;
2215 
2216 	from_len = sizeof (from);
2217 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
2218 	    &from_len);
2219 
2220 	(void) ndmpd_remove_file_handler(session, fd);
2221 	(void) close(session->ns_mover.md_listen_sock);
2222 	session->ns_mover.md_listen_sock = -1;
2223 
2224 	if (session->ns_mover.md_sock < 0) {
2225 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
2226 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
2227 		return;
2228 	}
2229 
2230 	(void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE,
2231 	    &flag, sizeof (flag));
2232 	ndmp_set_socket_nodelay(session->ns_mover.md_sock);
2233 	ndmp_set_socket_rcv_buf(session->ns_mover.md_sock, 60 * KILOBYTE);
2234 	ndmp_set_socket_snd_buf(session->ns_mover.md_sock, 60 * KILOBYTE);
2235 
2236 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
2237 
2238 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
2239 		if (start_mover_for_backup(session) < 0) {
2240 			ndmpd_mover_error(session,
2241 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
2242 			return;
2243 		}
2244 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
2245 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2246 		    ntohs(from.sin_port));
2247 	} else {
2248 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
2249 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2250 		    ntohs(from.sin_port));
2251 	}
2252 
2253 	NDMP_LOG(LOG_DEBUG, "Received connection");
2254 
2255 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2256 }
2257 
2258 /*
2259  * tape_read
2260  *
2261  * Reads a data record from tape. Detects and handles EOT conditions.
2262  *
2263  * Parameters:
2264  *   session (input) - session pointer.
2265  *   data    (input) - location to read data to.
2266  *
2267  * Returns:
2268  *    0 - operation aborted.
2269  *   -1 - tape read error.
2270  *   otherwise - number of bytes read.
2271  */
2272 static int
2273 tape_read(ndmpd_session_t *session, char *data)
2274 {
2275 	ssize_t n;
2276 	int err;
2277 	int count = session->ns_mover.md_record_size;
2278 
2279 	for (; ; ) {
2280 		n = read(session->ns_tape.td_fd, data, count);
2281 		if (n < 0) {
2282 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
2283 			return (TAPE_READ_ERR);
2284 		}
2285 		NS_ADD(rtape, n);
2286 
2287 		if (n == 0) {
2288 			if (!is_writer_running(session))
2289 				return (TAPE_NO_WRITER_ERR);
2290 
2291 			/*
2292 			 * End of media reached.
2293 			 * Notify client and wait for the client to
2294 			 * either abort the data operation or continue the
2295 			 * operation after changing the tape.
2296 			 */
2297 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2298 			    ++ndmp_log_msg_id,
2299 			    "End of tape reached. Load next tape");
2300 
2301 			NDMP_LOG(LOG_DEBUG,
2302 			    "End of tape reached. Load next tape");
2303 
2304 			err = change_tape(session);
2305 
2306 			/* Operation aborted or connection terminated? */
2307 			if (err < 0) {
2308 				/*
2309 				 * K.L. Go back one record if it is read
2310 				 * but not used.
2311 				 */
2312 
2313 				if (count != session->ns_mover.md_record_size) {
2314 					(void) ndmp_mtioctl(
2315 					    session->ns_tape.td_fd, MTBSR, 1);
2316 				}
2317 				return (0);
2318 			}
2319 			/* Retry the read from the new tape. */
2320 			continue;
2321 		}
2322 
2323 		/* Change to pass Veritas Netbackup prequal test. */
2324 		data += n;
2325 		count -= n;
2326 		if (count <= 0) {
2327 			session->ns_mover.md_record_num++;
2328 			session->ns_tape.td_record_count++;
2329 			return (n);
2330 		}
2331 	}
2332 }
2333 
2334 /*
2335  * change_tape
2336  *
2337  * Send a notify_pause request (protocol version 1) or
2338  * notify_mover_pause request (protocol version 2) to the
2339  * NDMP client to inform
2340  * the client that a tape volume change is required.
2341  * Process messages until the data/mover operation is either aborted
2342  * or continued.
2343  *
2344  * Parameters:
2345  *   client_data (input) - session pointer.
2346  *
2347  * Returns:
2348  *   0 - operation has been continued.
2349  *  -1 - operation has been aborted.
2350  */
2351 static int
2352 change_tape(ndmpd_session_t *session)
2353 {
2354 	ndmp_notify_mover_paused_request request;
2355 
2356 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2357 
2358 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
2359 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
2360 	else
2361 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
2362 
2363 	request.reason = session->ns_mover.md_pause_reason;
2364 	request.seek_position = long_long_to_quad(0LL);
2365 
2366 	NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
2367 	    session->ns_mover.md_pause_reason);
2368 
2369 	if (ndmp_send_request(session->ns_connection,
2370 	    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2371 	    (void *) &request, 0) < 0) {
2372 		NDMP_LOG(LOG_DEBUG,
2373 		    "Sending notify_mover_paused request");
2374 		return (-1);
2375 	}
2376 	/*
2377 	 * Wait for until the state is changed by
2378 	 * an abort or continue request.
2379 	 */
2380 	nlp_ref_nw(session);
2381 	for (; ; ) {
2382 		NDMP_LOG(LOG_DEBUG, "calling nlp_wait_nw()");
2383 
2384 		nlp_wait_nw(session);
2385 
2386 		if (nlp_event_rv_get(session) < 0) {
2387 			nlp_unref_nw(session);
2388 			return (-1);
2389 		}
2390 
2391 		if (session->ns_eof == TRUE) {
2392 			NDMP_LOG(LOG_DEBUG, "session->ns_eof == TRUE");
2393 			nlp_unref_nw(session);
2394 			return (-1);
2395 		}
2396 
2397 		switch (session->ns_mover.md_state) {
2398 		case NDMP_MOVER_STATE_ACTIVE:
2399 			NDMP_LOG(LOG_DEBUG,
2400 			    "mover.state: NDMP_MOVER_STATE_ACTIVE");
2401 
2402 			nlp_unref_nw(session);
2403 			session->ns_tape.td_record_count = 0;
2404 			return (0);
2405 
2406 		case NDMP_MOVER_STATE_PAUSED:
2407 			NDMP_LOG(LOG_DEBUG,
2408 			    "mover.state: NDMP_MOVER_STATE_PAUSED");
2409 			continue;
2410 
2411 		default:
2412 			NDMP_LOG(LOG_DEBUG, "default");
2413 			nlp_unref_nw(session);
2414 			return (-1);
2415 		}
2416 	}
2417 
2418 	/* nlp_unref_nw(session); - statement never reached */
2419 }
2420 
2421 
2422 /*
2423  * discard_data
2424  *
2425  * Read and discard data from the data connection.
2426  * Called when a module has called ndmpd_seek() prior to
2427  * reading all of the data from the previous seek.
2428  *
2429  * Parameters:
2430  *   session (input) - session pointer.
2431  *
2432  * Returns:
2433  *   number of bytes read and discarded.
2434  *  -1 - error.
2435  */
2436 static int
2437 discard_data(ndmpd_session_t *session, ulong_t length)
2438 {
2439 	int n;
2440 	char *addr;
2441 
2442 	if ((addr = ndmp_malloc(length)) == NULL)
2443 		return (-1);
2444 
2445 	/* Read and discard the data. */
2446 	n = read(session->ns_mover.md_sock, addr, length);
2447 	if (n < 0) {
2448 		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
2449 		free(addr);
2450 		return (-1);
2451 	}
2452 
2453 	free(addr);
2454 	return (n);
2455 }
2456 
2457 
2458 /*
2459  * mover_tape_read_one_buf
2460  *
2461  * Read one buffer from the tape. This is used by mover_tape_reader
2462  *
2463  * Parameters:
2464  *   session (input) - session pointer.
2465  *   buf (input) - buffer read
2466  *
2467  * Returns:
2468  *   0: on success
2469  *  -1: otherwise
2470  */
2471 static int
2472 mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2473 {
2474 	int n;
2475 
2476 	tlm_buffer_mark_empty(buf);
2477 
2478 	/*
2479 	 * If the end of the mover window has been reached,
2480 	 * then notify the client that a seek is needed.
2481 	 * Remove the file handler to prevent this function from
2482 	 * being called. The handler will be reinstalled in
2483 	 * ndmpd_mover_continue.
2484 	 */
2485 
2486 	if (session->ns_mover.md_position >=
2487 	    session->ns_mover.md_window_offset +
2488 	    session->ns_mover.md_window_length) {
2489 		ndmp_notify_mover_paused_request pause_request;
2490 
2491 		NDMP_LOG(LOG_DEBUG, "end of mover window");
2492 
2493 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2494 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2495 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2496 		pause_request.seek_position =
2497 		    long_long_to_quad(session->ns_mover.md_position);
2498 
2499 		if (ndmp_send_request(session->ns_connection,
2500 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2501 		    (void *) &pause_request, 0) < 0) {
2502 			NDMP_LOG(LOG_DEBUG,
2503 			    "Sending notify_mover_paused request");
2504 			ndmpd_mover_error(session,
2505 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
2506 		}
2507 		buf->tb_errno = EIO;
2508 		return (TAPE_READ_ERR);
2509 	}
2510 
2511 	n = tape_read(session, buf->tb_buffer_data);
2512 
2513 	NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
2514 
2515 	if (n <= 0) {
2516 		if (n < 0)
2517 			ndmpd_mover_error(session,
2518 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
2519 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
2520 		return (TAPE_READ_ERR);
2521 	}
2522 
2523 	buf->tb_full = TRUE;
2524 	buf->tb_buffer_size = session->ns_mover.md_record_size;
2525 
2526 	/*
2527 	 * Discard data if the current data stream position is
2528 	 * prior to the seek position. This is necessary if a seek
2529 	 * request set the seek pointer to a position that is not a
2530 	 * record boundary. The seek request handler can only position
2531 	 * to the start of a record.
2532 	 */
2533 	if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
2534 		session->ns_mover.md_position =
2535 		    session->ns_mover.md_seek_position;
2536 
2537 	return (0);
2538 }
2539 
2540 
2541 /*
2542  * mover_tape_reader
2543  *
2544  * Mover tape reader thread. It is launched when the mover is started
2545  * for restore.
2546  *
2547  * Parameters:
2548  *   session (input) - session pointer.
2549  *
2550  * Returns:
2551  *   0: on success
2552  *  -1: otherwise
2553  */
2554 int
2555 mover_tape_reader(ndmpd_session_t *session)
2556 {
2557 	int bidx;	/* buffer index */
2558 	int rv;
2559 	ndmp_lbr_params_t *nlp;
2560 	tlm_buffer_t *buf;
2561 	tlm_buffers_t *bufs;
2562 	tlm_cmd_t *lcmd;	/* Local command */
2563 	tlm_commands_t *cmds;	/* Commands structure */
2564 
2565 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2566 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2567 		return (-1);
2568 	}
2569 
2570 	cmds = &nlp->nlp_cmds;
2571 	lcmd = cmds->tcs_command;
2572 	bufs = lcmd->tc_buffers;
2573 
2574 	lcmd->tc_ref++;
2575 	cmds->tcs_reader_count++;
2576 
2577 	/*
2578 	 * Let our parent thread know that we are running.
2579 	 */
2580 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
2581 
2582 	buf = tlm_buffer_in_buf(bufs, &bidx);
2583 	while (cmds->tcs_reader == TLM_RESTORE_RUN &&
2584 	    lcmd->tc_reader == TLM_RESTORE_RUN) {
2585 		buf = tlm_buffer_in_buf(bufs, NULL);
2586 
2587 		if (buf->tb_full) {
2588 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2589 			/*
2590 			 * The buffer is still full, wait for the consumer
2591 			 * thread to use it.
2592 			 */
2593 			tlm_buffer_out_buf_timed_wait(bufs, 100);
2594 
2595 		} else {
2596 			NDMP_LOG(LOG_DEBUG, "r%d", bidx);
2597 
2598 			rv = mover_tape_read_one_buf(session, buf);
2599 			/*
2600 			 * If there was an error while reading, such as
2601 			 * end of stream.
2602 			 */
2603 			if (rv < 0) {
2604 				NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
2605 				break;
2606 			}
2607 
2608 			/*
2609 			 * Can we do more buffering?
2610 			 */
2611 			if (is_buffer_erroneous(buf)) {
2612 				NDMP_LOG(LOG_DEBUG,
2613 				    "Exiting, errno: %d, eot: %d, eof: %d",
2614 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
2615 				break;
2616 			}
2617 
2618 			(void) tlm_buffer_advance_in_idx(bufs);
2619 			tlm_buffer_release_in_buf(bufs);
2620 			bidx = bufs->tbs_buffer_in;
2621 		}
2622 	}
2623 
2624 	/* If the consumer is waiting for us, wake it up. */
2625 	tlm_buffer_release_in_buf(bufs);
2626 
2627 	/*
2628 	 * Clean up.
2629 	 */
2630 	cmds->tcs_reader_count--;
2631 	lcmd->tc_ref--;
2632 	lcmd->tc_writer = TLM_STOP;
2633 	return (0);
2634 }
2635 
2636 
2637 /*
2638  * mover_socket_write_one_buf
2639  *
2640  * Write one buffer to the network socket. This is used by mover_socket_writer
2641  *
2642  * Parameters:
2643  *   session (input) - session pointer.
2644  *   buf (input) - buffer read
2645  *
2646  * Returns:
2647  *   0: on success
2648  *  -1: otherwise
2649  */
2650 static int
2651 mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2652 {
2653 	int n;
2654 
2655 	/* Write the data to the data connection. */
2656 	errno = 0;
2657 	n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
2658 	    buf->tb_buffer_size);
2659 
2660 	NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
2661 
2662 	if (n < 0) {
2663 		NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2664 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
2665 		return (-1);
2666 	}
2667 
2668 	session->ns_mover.md_position += n;
2669 	session->ns_mover.md_bytes_left_to_read -= n;
2670 	tlm_buffer_mark_empty(buf);
2671 
2672 	/*
2673 	 * If the read limit has been reached,
2674 	 * then remove the file handler to prevent this
2675 	 * function from getting called. The next mover_read request
2676 	 * will reinstall the handler.
2677 	 */
2678 	if (session->ns_mover.md_bytes_left_to_read == 0) {
2679 		NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
2680 		(void) ndmpd_remove_file_handler(session,
2681 		    session->ns_mover.md_sock);
2682 		return (-1);
2683 	}
2684 
2685 	return (0);
2686 }
2687 
2688 
2689 
2690 /*
2691  * mover_socket_writer
2692  *
2693  * Mover's socket writer thread. This thread sends the read buffer
2694  * from the tape to the data server through the network socket.
2695  *
2696  * Parameters:
2697  *   session (input) - session pointer.
2698  *
2699  * Returns:
2700  *   0: on success
2701  *  -1: otherwise
2702  */
2703 int
2704 mover_socket_writer(ndmpd_session_t *session)
2705 {
2706 	int bidx;	/* buffer index */
2707 	ndmp_lbr_params_t *nlp;
2708 	tlm_buffer_t *buf;
2709 	tlm_buffers_t *bufs;
2710 	tlm_cmd_t *lcmd;	/* Local command */
2711 	tlm_commands_t *cmds;	/* Commands structure */
2712 
2713 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2714 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2715 		return (-1);
2716 	}
2717 
2718 	cmds = &nlp->nlp_cmds;
2719 	lcmd = cmds->tcs_command;
2720 	bufs = lcmd->tc_buffers;
2721 
2722 	lcmd->tc_ref++;
2723 	cmds->tcs_writer_count++;
2724 
2725 	/*
2726 	 * Let our parent thread know that we are running.
2727 	 */
2728 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
2729 
2730 	bidx = bufs->tbs_buffer_out;
2731 	while (cmds->tcs_writer != (int)TLM_ABORT &&
2732 	    lcmd->tc_writer != (int)TLM_ABORT) {
2733 		buf = &bufs->tbs_buffer[bidx];
2734 
2735 		if (buf->tb_full) {
2736 			NDMP_LOG(LOG_DEBUG, "w%d", bidx);
2737 
2738 			if (mover_socket_write_one_buf(session, buf) < 0) {
2739 				NDMP_LOG(LOG_DEBUG,
2740 				    "mover_socket_write_one_buf() < 0");
2741 				break;
2742 			}
2743 
2744 			(void) tlm_buffer_advance_out_idx(bufs);
2745 			tlm_buffer_release_out_buf(bufs);
2746 			bidx = bufs->tbs_buffer_out;
2747 		} else {
2748 			if (lcmd->tc_writer != TLM_RESTORE_RUN) {
2749 				/* No more data is coming, time to exit */
2750 				NDMP_LOG(LOG_DEBUG, "Time to exit");
2751 				break;
2752 			}
2753 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
2754 			/*
2755 			 * The buffer is not full, wait for the producer
2756 			 * thread to fill it.
2757 			 */
2758 			tlm_buffer_in_buf_timed_wait(bufs, 100);
2759 		}
2760 	}
2761 
2762 	if (cmds->tcs_writer == (int)TLM_ABORT)
2763 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
2764 	if (lcmd->tc_writer == (int)TLM_ABORT)
2765 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
2766 
2767 	/* If the producer is waiting for us, wake it up. */
2768 	tlm_buffer_release_out_buf(bufs);
2769 
2770 	/*
2771 	 * Clean up.
2772 	 */
2773 	cmds->tcs_writer_count--;
2774 	lcmd->tc_ref--;
2775 	lcmd->tc_reader = TLM_STOP;
2776 	return (0);
2777 }
2778 
2779 
2780 /*
2781  * start_mover_for_restore
2782  *
2783  * Creates the mover tape reader and network writer threads for
2784  * the mover to perform the 3-way restore.
2785  *
2786  * Parameters:
2787  *   session (input) - session pointer.
2788  *
2789  * Returns:
2790  *   0: on success
2791  *  -1: otherwise
2792  */
2793 static int
2794 start_mover_for_restore(ndmpd_session_t *session)
2795 {
2796 	ndmp_lbr_params_t *nlp;
2797 	tlm_commands_t *cmds;
2798 	long xfer_size;
2799 	int rc;
2800 
2801 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2802 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2803 		return (-1);
2804 	}
2805 
2806 	cmds = &nlp->nlp_cmds;
2807 	(void) memset(cmds, 0, sizeof (*cmds));
2808 	cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
2809 	xfer_size = ndmp_buffer_get_size(session);
2810 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2811 	if (cmds->tcs_command == NULL)
2812 		return (-1);
2813 
2814 	cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
2815 	cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
2816 
2817 	/*
2818 	 * We intentionnally don't wait for the threads to start since the
2819 	 * reply of the request (which resulted in calling this function)
2820 	 * must be sent to the client before probable errors are sent
2821 	 * to the client.
2822 	 */
2823 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session);
2824 	if (rc == 0) {
2825 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
2826 	} else {
2827 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
2828 		    strerror(rc));
2829 		return (-1);
2830 	}
2831 
2832 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session);
2833 	if (rc == 0) {
2834 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
2835 	} else {
2836 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
2837 		    strerror(rc));
2838 		return (-1);
2839 	}
2840 
2841 	tlm_release_reader_writer_ipc(cmds->tcs_command);
2842 	return (0);
2843 }
2844 
2845 
2846 /*
2847  * mover_socket_read_one_buf
2848  *
2849  * Read one buffer from the network socket for the mover. This is used
2850  * by mover_socket_reader
2851  *
2852  * Parameters:
2853  *   session (input) - session pointer.
2854  *   buf (input) - buffer read
2855  *   read_size (input) - size to be read
2856  *
2857  * Returns:
2858  *   0: on success
2859  *  -1: otherwise
2860  */
2861 static int
2862 mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
2863     long read_size)
2864 {
2865 	int n, index;
2866 	long toread;
2867 
2868 	tlm_buffer_mark_empty(buf);
2869 	for (index = 0, toread = read_size; toread > 0; ) {
2870 		errno = 0;
2871 		NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
2872 
2873 		n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
2874 		    toread);
2875 		if (n == 0) {
2876 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
2877 			break;
2878 		} else if (n > 0) {
2879 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
2880 			index += n;
2881 			toread -= n;
2882 		} else {
2883 			buf->tb_eof = TRUE;
2884 			buf->tb_errno = errno;
2885 			buf->tb_buffer_size = 0;
2886 			NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2887 			return (-1);
2888 		}
2889 	}
2890 
2891 	if (index > 0) {
2892 		buf->tb_full = TRUE;
2893 		buf->tb_buffer_size = read_size;
2894 		if (read_size > 0)
2895 			(void) memset(&buf->tb_buffer_data[index], 0,
2896 			    read_size - index);
2897 	} else {
2898 		buf->tb_eof = TRUE;
2899 		buf->tb_buffer_size = 0;
2900 	}
2901 
2902 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2903 	    " errno: %d, size: %d, data: 0x%x",
2904 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2905 	    buf->tb_buffer_size, buf->tb_buffer_data);
2906 
2907 	return (0);
2908 }
2909 
2910 
2911 
2912 /*
2913  * mover_socket_reader
2914  *
2915  * Mover socket reader thread. This is used when reading data from the
2916  * network socket for performing remote backups.
2917  *
2918  * Parameters:
2919  *   session (input) - session pointer.
2920  *
2921  * Returns:
2922  *   0: on success
2923  *  -1: otherwise
2924  */
2925 int
2926 mover_socket_reader(ndmpd_session_t *session)
2927 {
2928 	int bidx;	/* buffer index */
2929 	ndmp_lbr_params_t *nlp;
2930 	tlm_buffer_t *buf;
2931 	tlm_buffers_t *bufs;
2932 	tlm_cmd_t *lcmd;	/* Local command */
2933 	tlm_commands_t *cmds;	/* Commands structure */
2934 	static int nr = 0;
2935 
2936 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2937 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2938 		return (-1);
2939 	}
2940 
2941 	cmds = &nlp->nlp_cmds;
2942 	lcmd = cmds->tcs_command;
2943 	bufs = lcmd->tc_buffers;
2944 
2945 	lcmd->tc_ref++;
2946 	cmds->tcs_reader_count++;
2947 
2948 	/*
2949 	 * Let our parent thread know that we are running.
2950 	 */
2951 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
2952 
2953 	bidx = bufs->tbs_buffer_in;
2954 	while (cmds->tcs_reader == TLM_BACKUP_RUN &&
2955 	    lcmd->tc_reader == TLM_BACKUP_RUN) {
2956 		buf = &bufs->tbs_buffer[bidx];
2957 
2958 		if (buf->tb_full) {
2959 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2960 			/*
2961 			 * The buffer is still full, wait for the consumer
2962 			 * thread to use it.
2963 			 */
2964 			tlm_buffer_out_buf_timed_wait(bufs, 100);
2965 		} else {
2966 			NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
2967 
2968 			(void) mover_socket_read_one_buf(session, buf,
2969 			    bufs->tbs_data_transfer_size);
2970 
2971 			/*
2972 			 * Can we do more buffering?
2973 			 */
2974 			if (is_buffer_erroneous(buf)) {
2975 				NDMP_LOG(LOG_DEBUG,
2976 				    "Exiting, errno: %d, eot: %d, eof: %d",
2977 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
2978 				break;
2979 			}
2980 
2981 			(void) tlm_buffer_advance_in_idx(bufs);
2982 			tlm_buffer_release_in_buf(bufs);
2983 			bidx = bufs->tbs_buffer_in;
2984 		}
2985 	}
2986 
2987 	if (cmds->tcs_reader != TLM_BACKUP_RUN)
2988 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
2989 	if (lcmd->tc_reader != TLM_BACKUP_RUN)
2990 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
2991 	NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
2992 
2993 	/* If the consumer is waiting for us, wake it up. */
2994 	tlm_buffer_release_in_buf(bufs);
2995 
2996 	/*
2997 	 * Clean up.
2998 	 */
2999 	cmds->tcs_reader_count--;
3000 	lcmd->tc_ref--;
3001 	lcmd->tc_writer = TLM_STOP;
3002 	return (0);
3003 }
3004 
3005 
3006 /*
3007  * mover_tape_writer_one_buf
3008  *
3009  * Write one buffer for the mover to the local tape device. This is
3010  * used by mover_tape_writer thread.
3011  *
3012  * Parameters:
3013  *   session (input) - session pointer.
3014  *   buf (input) - buffer read
3015  *
3016  * Returns:
3017  *   0: on success
3018  *  -1: otherwise
3019  */
3020 static int
3021 mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
3022 {
3023 	int n;
3024 
3025 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
3026 	    " errno: %d, size: %d, data: 0x%x",
3027 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
3028 	    buf->tb_buffer_size, buf->tb_buffer_data);
3029 
3030 	n = mover_tape_write_v3(session, buf->tb_buffer_data,
3031 	    buf->tb_buffer_size);
3032 
3033 	NDMP_LOG(LOG_DEBUG, "n: %d", n);
3034 
3035 	if (n <= 0) {
3036 		ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
3037 		    : NDMP_MOVER_HALT_INTERNAL_ERROR));
3038 		return (-1);
3039 	}
3040 	session->ns_mover.md_position += n;
3041 	session->ns_mover.md_data_written += n;
3042 	session->ns_mover.md_record_num++;
3043 
3044 	NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
3045 	tlm_buffer_mark_empty(buf);
3046 
3047 	return (0);
3048 }
3049 
3050 
3051 /*
3052  * mover_tape_writer
3053  *
3054  * Mover tape writer thread. This is used for performing remote backups
3055  * in a 3-way configuration. It writes the data from network socket to
3056  * the locally attached tape device.
3057  *
3058  * Parameters:
3059  *   session (input) - session pointer.
3060  *
3061  * Returns:
3062  *   0: on success
3063  *  -1: otherwise
3064  */
3065 int
3066 mover_tape_writer(ndmpd_session_t *session)
3067 {
3068 	int bidx;
3069 	ndmp_lbr_params_t *nlp;
3070 	tlm_buffer_t *buf;
3071 	tlm_buffers_t *bufs;
3072 	tlm_cmd_t *lcmd;
3073 	tlm_commands_t *cmds;
3074 	static int nw = 0;
3075 
3076 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3077 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3078 		return (-1);
3079 	}
3080 
3081 	cmds = &nlp->nlp_cmds;
3082 	lcmd = cmds->tcs_command;
3083 	bufs = lcmd->tc_buffers;
3084 
3085 	lcmd->tc_ref++;
3086 	cmds->tcs_writer_count++;
3087 
3088 	/*
3089 	 * Let our parent thread know that we are running.
3090 	 */
3091 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
3092 
3093 	bidx = bufs->tbs_buffer_out;
3094 	buf = &bufs->tbs_buffer[bidx];
3095 	while (cmds->tcs_writer != (int)TLM_ABORT &&
3096 	    lcmd->tc_writer != (int)TLM_ABORT) {
3097 		if (buf->tb_full) {
3098 			NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
3099 
3100 			if (mover_tape_write_one_buf(session, buf) < 0) {
3101 				NDMP_LOG(LOG_DEBUG,
3102 				    "mover_tape_write_one_buf() failed");
3103 				break;
3104 			}
3105 
3106 			(void) tlm_buffer_advance_out_idx(bufs);
3107 			tlm_buffer_release_out_buf(bufs);
3108 			bidx = bufs->tbs_buffer_out;
3109 			buf = &bufs->tbs_buffer[bidx];
3110 		} else {
3111 			if (lcmd->tc_writer != TLM_BACKUP_RUN) {
3112 				/* No more data is coming, time to exit */
3113 				NDMP_LOG(LOG_DEBUG, "Time to exit");
3114 				break;
3115 			}
3116 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
3117 			/*
3118 			 * The buffer is not full, wait for the producer
3119 			 * thread to fill it.
3120 			 */
3121 			tlm_buffer_in_buf_timed_wait(bufs, 100);
3122 		}
3123 	}
3124 
3125 	if (cmds->tcs_writer == (int)TLM_ABORT)
3126 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
3127 	if (lcmd->tc_writer == (int)TLM_ABORT)
3128 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
3129 	NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
3130 
3131 	if (buf->tb_errno == 0) {
3132 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3133 	} else {
3134 		NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
3135 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
3136 	}
3137 
3138 	/* If the producer is waiting for us, wake it up. */
3139 	tlm_buffer_release_out_buf(bufs);
3140 
3141 	/*
3142 	 * Clean up.
3143 	 */
3144 	cmds->tcs_writer_count--;
3145 	lcmd->tc_ref--;
3146 	lcmd->tc_reader = TLM_STOP;
3147 	return (0);
3148 }
3149 
3150 
3151 /*
3152  * start_mover_for_backup
3153  *
3154  * Starts a remote backup by running socket reader and tape
3155  * writer threads. The mover runs a remote backup in a 3-way backup
3156  * configuration.
3157  *
3158  * Parameters:
3159  *   session (input) - session pointer.
3160  *
3161  * Returns:
3162  *   0: on success
3163  *  -1: otherwise
3164  */
3165 static int
3166 start_mover_for_backup(ndmpd_session_t *session)
3167 {
3168 	ndmp_lbr_params_t *nlp;
3169 	tlm_commands_t *cmds;
3170 	int rc;
3171 
3172 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3173 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3174 		return (-1);
3175 	}
3176 
3177 	cmds = &nlp->nlp_cmds;
3178 	(void) memset(cmds, 0, sizeof (*cmds));
3179 	cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
3180 	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
3181 	    session->ns_mover.md_record_size);
3182 	if (cmds->tcs_command == NULL)
3183 		return (-1);
3184 
3185 	cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
3186 	cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
3187 
3188 	/*
3189 	 * We intentionally don't wait for the threads to start since the
3190 	 * reply of the request (which resulted in calling this function)
3191 	 * must be sent to the client before probable errors are sent
3192 	 * to the client.
3193 	 */
3194 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session);
3195 	if (rc == 0) {
3196 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
3197 	} else {
3198 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
3199 		    strerror(rc));
3200 		return (-1);
3201 	}
3202 
3203 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session);
3204 	if (rc == 0) {
3205 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
3206 	} else {
3207 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
3208 		    strerror(rc));
3209 		return (-1);
3210 	}
3211 
3212 	tlm_release_reader_writer_ipc(cmds->tcs_command);
3213 	return (0);
3214 }
3215 
3216 
3217 /*
3218  * is_writer_running
3219  *
3220  * Find out if the writer thread has started or not.
3221  *
3222  * Parameters:
3223  *   session (input) - session pointer.
3224  *
3225  * Returns:
3226  *   0: not started
3227  *   non-zero: started
3228  *	Note: non-zero is also returned if the backup type is
3229  *		neither TAR nor DUMP.  I.e. the is_writer_running()
3230  *		check does not apply in this case and things should
3231  * 		appear successful.
3232  */
3233 static boolean_t
3234 is_writer_running(ndmpd_session_t *session)
3235 {
3236 	boolean_t rv;
3237 	ndmp_lbr_params_t *nlp;
3238 
3239 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3240 		return (1);
3241 
3242 	if (session == NULL)
3243 		rv = 0;
3244 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
3245 		rv = 0;
3246 	else
3247 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3248 
3249 	return (rv);
3250 }
3251 
3252 
3253 /*
3254  * is_writer_running_v3
3255  *
3256  * Find out if the writer thread has started or not.
3257  *
3258  * Parameters:
3259  *   session (input) - session pointer.
3260  *
3261  * Returns:
3262  *   0: not started
3263  *   non-zero: started
3264  *	Note: non-zero is also returned if the backup type is
3265  *		neither TAR nor DUMP.  I.e. the is_writer_running()
3266  *		check does not apply in this case and things should
3267  * 		appear successful.
3268  */
3269 static boolean_t
3270 is_writer_running_v3(ndmpd_session_t *session)
3271 {
3272 	boolean_t rv;
3273 	ndmp_lbr_params_t *nlp;
3274 
3275 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3276 		return (1);
3277 
3278 	if (session == NULL)
3279 		rv = 0;
3280 	else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
3281 		rv = 1;
3282 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
3283 		rv = 0;
3284 	else
3285 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3286 
3287 	return (rv);
3288 }
3289 
3290 
3291 /*
3292  * ndmpd_mover_wait_v3
3293  *
3294  * Take the mover state to PAUSED state
3295  *
3296  * Parameters:
3297  *   session (input) - session pointer.
3298  *
3299  * Returns:
3300  *   0: on success
3301  *  -1: otherwise
3302  */
3303 int
3304 ndmpd_mover_wait_v3(ndmpd_session_t *session)
3305 {
3306 	int rv = 0;
3307 
3308 	nlp_ref_nw(session);
3309 	for (; ; ) {
3310 		nlp_wait_nw(session);
3311 
3312 		if (nlp_event_rv_get(session) < 0) {
3313 			rv = -1;
3314 			break;
3315 		}
3316 		if (session->ns_eof) {
3317 			NDMP_LOG(LOG_DEBUG, "session->ns_eof");
3318 			rv = -1;
3319 			break;
3320 		}
3321 		if (session->ns_data.dd_abort) {
3322 			NDMP_LOG(LOG_DEBUG, "data.abort");
3323 			rv = -1;
3324 			break;
3325 		}
3326 		if (session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
3327 			NDMP_LOG(LOG_DEBUG,
3328 			    "mover.state: NDMP_MOVER_STATE_ACTIVE");
3329 			session->ns_tape.td_record_count = 0;
3330 			rv = 0;
3331 			break;
3332 		} else if (session->ns_mover.md_state ==
3333 		    NDMP_MOVER_STATE_PAUSED) {
3334 			NDMP_LOG(LOG_DEBUG,
3335 			    "mover.state: NDMP_MOVER_STATE_PAUSED");
3336 		} else {
3337 			NDMP_LOG(LOG_DEBUG, "default");
3338 			rv = -1;
3339 			break;
3340 		}
3341 	}
3342 
3343 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
3344 	nlp_unref_nw(session);
3345 	return (rv);
3346 }
3347 
3348 /*
3349  * ndmpd_mover_error_send
3350  *
3351  * This function sends the notify message to the client.
3352  *
3353  * Parameters:
3354  *   session (input) - session pointer.
3355  *   reason  (input) - halt reason.
3356  *
3357  * Returns:
3358  *   Error code
3359  */
3360 int
3361 ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3362 {
3363 	ndmp_notify_mover_halted_request req;
3364 
3365 	req.reason = reason;
3366 	req.text_reason = "";
3367 
3368 	return (ndmp_send_request(session->ns_connection,
3369 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3370 }
3371 
3372 
3373 /*
3374  * ndmpd_mover_error_send_v4
3375  *
3376  * This function sends the notify message to the client.
3377  *
3378  * Parameters:
3379  *   session (input) - session pointer.
3380  *   reason  (input) - halt reason.
3381  *
3382  * Returns:
3383  *   Error code
3384  */
3385 int
3386 ndmpd_mover_error_send_v4(ndmpd_session_t *session,
3387     ndmp_mover_halt_reason reason)
3388 {
3389 	ndmp_notify_mover_halted_request_v4 req;
3390 
3391 	req.reason = reason;
3392 
3393 	return (ndmp_send_request(session->ns_connection,
3394 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3395 }
3396 
3397 
3398 /*
3399  * ndmpd_mover_error
3400  *
3401  * This function is called when an unrecoverable mover error
3402  * has been detected. A notify message is sent to the client and the
3403  * mover is placed into the halted state.
3404  *
3405  * Parameters:
3406  *   session (input) - session pointer.
3407  *   reason  (input) - halt reason.
3408  *
3409  * Returns:
3410  *   void.
3411  */
3412 void
3413 ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3414 {
3415 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
3416 	    (session->ns_protocol_version > NDMPV2 &&
3417 	    session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
3418 		return;
3419 
3420 	if (session->ns_protocol_version == NDMPV4) {
3421 		if (ndmpd_mover_error_send_v4(session, reason) < 0)
3422 			NDMP_LOG(LOG_DEBUG,
3423 			    "Error sending notify_mover_halted request");
3424 	} else {
3425 		/* No media error in V3 */
3426 		if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
3427 			reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
3428 		if (ndmpd_mover_error_send(session, reason) < 0)
3429 			NDMP_LOG(LOG_DEBUG,
3430 			    "Error sending notify_mover_halted request");
3431 	}
3432 
3433 	if (session->ns_mover.md_listen_sock != -1) {
3434 		(void) ndmpd_remove_file_handler(session,
3435 		    session->ns_mover.md_listen_sock);
3436 		(void) close(session->ns_mover.md_listen_sock);
3437 		session->ns_mover.md_listen_sock = -1;
3438 	}
3439 	if (session->ns_mover.md_sock != -1) {
3440 		(void) ndmpd_remove_file_handler(session,
3441 		    session->ns_mover.md_sock);
3442 		(void) close(session->ns_mover.md_sock);
3443 		session->ns_mover.md_sock = -1;
3444 	}
3445 
3446 	session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
3447 	session->ns_mover.md_halt_reason = reason;
3448 }
3449 
3450 
3451 /*
3452  * mover_pause_v3
3453  *
3454  * Send an ndmp_notify_mover_paused request to the
3455  * NDMP client to inform the client that its attention is required.
3456  * Process messages until the data/mover operation is either aborted
3457  * or continued.
3458  *
3459  * Parameters:
3460  *   client_data (input) - session pointer.
3461  *   reason (input) - pause reason.
3462  *
3463  * Returns:
3464  *   0 - operation has been continued.
3465  *  -1 - operation has been aborted.
3466  */
3467 static int
3468 mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
3469 {
3470 	int rv;
3471 	ndmp_notify_mover_paused_request request;
3472 
3473 	rv = 0;
3474 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3475 	session->ns_mover.md_pause_reason = reason;
3476 	session->ns_mover.md_pre_cond = FALSE;
3477 
3478 	request.reason = session->ns_mover.md_pause_reason;
3479 	request.seek_position =
3480 	    long_long_to_quad(session->ns_mover.md_position);
3481 
3482 	if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
3483 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
3484 		NDMP_LOG(LOG_DEBUG,
3485 		    "Error sending notify_mover_paused_request");
3486 		return (-1);
3487 	}
3488 
3489 	/*
3490 	 * 3-way operations are single-thread.  The same thread
3491 	 * should process the messages.
3492 	 *
3493 	 * 2-way operations are multi-thread.  The main thread
3494 	 * processes the messages.  We just need to wait and
3495 	 * see if the mover state changes or the operation aborts.
3496 	 */
3497 	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
3498 		/*
3499 		 * Process messages until the state is changed by
3500 		 * an abort, continue, or close request .
3501 		 */
3502 		for (; ; ) {
3503 			if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
3504 				return (-1);
3505 
3506 			if (session->ns_eof == TRUE)
3507 				return (-1);
3508 
3509 			switch (session->ns_mover.md_state) {
3510 			case NDMP_MOVER_STATE_ACTIVE:
3511 				session->ns_tape.td_record_count = 0;
3512 				return (0);
3513 
3514 			case NDMP_MOVER_STATE_PAUSED:
3515 				continue;
3516 
3517 			default:
3518 				return (-1);
3519 			}
3520 		}
3521 
3522 	} else {
3523 		if (session->ns_mover.md_data_addr.addr_type ==
3524 		    NDMP_ADDR_LOCAL) {
3525 			rv = ndmpd_mover_wait_v3(session);
3526 		} else {
3527 			NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
3528 			    session->ns_mover.md_data_addr.addr_type);
3529 			rv = -1;
3530 		}
3531 	}
3532 
3533 	return (rv);
3534 }
3535 
3536 
3537 /*
3538  * mover_tape_write_v3
3539  *
3540  * Writes a data record to tape. Detects and handles EOT conditions.
3541  *
3542  * Parameters:
3543  *   session (input) - session pointer.
3544  *   data    (input) - data to be written.
3545  *   length  (input) - length of data to be written.
3546  *
3547  * Returns:
3548  *    0 - operation aborted by client.
3549  *   -1 - error.
3550  *   otherwise - number of bytes written.
3551  */
3552 static int
3553 mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
3554 {
3555 	ssize_t n;
3556 	ssize_t count = length;
3557 
3558 	while (count > 0) {
3559 		/*
3560 		 * Enforce mover window on write.
3561 		 */
3562 		if (session->ns_mover.md_position >=
3563 		    session->ns_mover.md_window_offset +
3564 		    session->ns_mover.md_window_length) {
3565 			NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
3566 
3567 			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW) < 0)
3568 				/* Operation aborted or connection terminated */
3569 				return (-1);
3570 
3571 		}
3572 
3573 		n = write(session->ns_tape.td_fd, data, count);
3574 		if (n < 0) {
3575 			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3576 			return (-1);
3577 		} else if (n > 0) {
3578 			NS_ADD(wtape, n);
3579 			count -= n;
3580 			data += n;
3581 			session->ns_tape.td_record_count++;
3582 		}
3583 
3584 		/* EOM handling */
3585 		if (count > 0) {
3586 			struct mtget mtstatus;
3587 
3588 			(void) ioctl(session->ns_tape.td_fd, MTIOCGET,
3589 			    &mtstatus);
3590 			NDMP_LOG(LOG_DEBUG, "EOM detected (%d written bytes, "
3591 			    "mover record %d, file #%d, block #%d)", n,
3592 			    session->ns_tape.td_record_count,
3593 			    mtstatus.mt_fileno, mtstatus.mt_blkno);
3594 
3595 			/*
3596 			 * Notify the client to either abort the operation
3597 			 * or change the tape.
3598 			 */
3599 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3600 			    ++ndmp_log_msg_id,
3601 			    "End of tape reached. Load next tape");
3602 
3603 			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM) < 0)
3604 				/* Operation aborted or connection terminated */
3605 				return (-1);
3606 		}
3607 	}
3608 
3609 	return (length);
3610 }
3611 
3612 
3613 /*
3614  * mover_tape_flush_v3
3615  *
3616  * Writes all remaining buffered data to tape. A partial record is
3617  * padded out to a full record with zeros.
3618  *
3619  * Parameters:
3620  *   session (input) - session pointer.
3621  *   data    (input) - data to be written.
3622  *   length  (input) - length of data to be written.
3623  *
3624  * Returns:
3625  *   -1 - error.
3626  *   otherwise - number of bytes written.
3627  */
3628 static int
3629 mover_tape_flush_v3(ndmpd_session_t *session)
3630 {
3631 	int n;
3632 
3633 	if (session->ns_mover.md_w_index == 0)
3634 		return (0);
3635 
3636 	(void) memset((void*)&session->ns_mover.md_buf[session->
3637 	    ns_mover.md_w_index], 0,
3638 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3639 
3640 	n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3641 	    session->ns_mover.md_record_size);
3642 	if (n < 0) {
3643 		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3644 		return (-1);
3645 	}
3646 
3647 	session->ns_mover.md_w_index = 0;
3648 	session->ns_mover.md_position += n;
3649 	return (n);
3650 }
3651 
3652 
3653 /*
3654  * ndmpd_local_write_v3
3655  *
3656  * Buffers and writes data to the tape device.
3657  * A full tape record is buffered before being written.
3658  *
3659  * Parameters:
3660  *   session    (input) - session pointer.
3661  *   data       (input) - data to be written.
3662  *   length     (input) - data length.
3663  *
3664  * Returns:
3665  *   0 - data successfully written.
3666  *  -1 - error.
3667  */
3668 int
3669 ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
3670 {
3671 	ulong_t count = 0;
3672 	ssize_t n;
3673 	ulong_t len;
3674 
3675 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
3676 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
3677 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
3678 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
3679 		return (-1);
3680 	}
3681 
3682 	/*
3683 	 * A length of 0 indicates that any buffered data should be
3684 	 * flushed to tape.
3685 	 */
3686 	if (length == 0) {
3687 		if (session->ns_mover.md_w_index == 0)
3688 			return (0);
3689 
3690 		(void) memset((void*)&session->ns_mover.md_buf[session->
3691 		    ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
3692 		    session->ns_mover.md_w_index);
3693 
3694 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3695 		    session->ns_mover.md_record_size);
3696 		if (n <= 0) {
3697 			ndmpd_mover_error(session,
3698 			    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3699 			    NDMP_MOVER_HALT_MEDIA_ERROR));
3700 			return (-1);
3701 		}
3702 
3703 		session->ns_mover.md_position += n;
3704 		session->ns_mover.md_data_written +=
3705 		    session->ns_mover.md_w_index;
3706 		session->ns_mover.md_record_num++;
3707 		session->ns_mover.md_w_index = 0;
3708 		return (0);
3709 	}
3710 
3711 	/* Break the data into records. */
3712 	while (count < length) {
3713 		/*
3714 		 * Determine if data needs to be buffered or
3715 		 * can be written directly from user supplied location.
3716 		 * We can fast path the write if there is no pending
3717 		 * buffered data and there is at least a full records worth
3718 		 * of data to be written.
3719 		 */
3720 		if (session->ns_mover.md_w_index == 0 &&
3721 		    length - count >= session->ns_mover.md_record_size) {
3722 			n = mover_tape_write_v3(session, &data[count],
3723 			    session->ns_mover.md_record_size);
3724 			if (n <= 0) {
3725 				ndmpd_mover_error(session,
3726 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3727 				    NDMP_MOVER_HALT_MEDIA_ERROR));
3728 				return (-1);
3729 			}
3730 
3731 			session->ns_mover.md_position += n;
3732 			session->ns_mover.md_data_written += n;
3733 			session->ns_mover.md_record_num++;
3734 			count += n;
3735 			continue;
3736 		}
3737 
3738 		/* Buffer the data */
3739 		len = length - count;
3740 		if (len > session->ns_mover.md_record_size -
3741 		    session->ns_mover.md_w_index)
3742 			len = session->ns_mover.md_record_size -
3743 			    session->ns_mover.md_w_index;
3744 
3745 		(void) memcpy(&session->ns_mover.md_buf[session->
3746 		    ns_mover.md_w_index], &data[count], len);
3747 		session->ns_mover.md_w_index += len;
3748 		count += len;
3749 
3750 		/* Write the buffer if its full */
3751 		if (session->ns_mover.md_w_index ==
3752 		    session->ns_mover.md_record_size) {
3753 			n = mover_tape_write_v3(session,
3754 			    session->ns_mover.md_buf,
3755 			    session->ns_mover.md_record_size);
3756 			if (n <= 0) {
3757 				ndmpd_mover_error(session,
3758 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3759 				    NDMP_MOVER_HALT_MEDIA_ERROR));
3760 				return (-1);
3761 			}
3762 
3763 			session->ns_mover.md_position += n;
3764 			session->ns_mover.md_data_written += n;
3765 			session->ns_mover.md_record_num++;
3766 			session->ns_mover.md_w_index = 0;
3767 		}
3768 	}
3769 
3770 	return (0);
3771 }
3772 
3773 
3774 /*
3775  * mover_data_read_v3
3776  *
3777  * Reads backup data from the data connection and writes the
3778  * received data to the tape device.
3779  *
3780  * Parameters:
3781  *   cookie  (input) - session pointer.
3782  *   fd      (input) - file descriptor.
3783  *   mode    (input) - select mode.
3784  *
3785  * Returns:
3786  *   void.
3787  */
3788 /*ARGSUSED*/
3789 static void
3790 mover_data_read_v3(void *cookie, int fd, ulong_t mode)
3791 {
3792 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3793 	int n;
3794 	ulong_t index;
3795 
3796 	n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
3797 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3798 
3799 	/*
3800 	 * Since this function is only called when select believes data
3801 	 * is available to be read, a return of zero indicates the
3802 	 * connection has been closed.
3803 	 */
3804 	if (n <= 0) {
3805 		if (n < 0 && errno == EWOULDBLOCK) {
3806 			NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
3807 			return;
3808 		}
3809 		NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
3810 
3811 		/* Save the index since mover_tape_flush_v3 resets it. */
3812 		index = session->ns_mover.md_w_index;
3813 
3814 		/* Flush any buffered data to tape. */
3815 		if (mover_tape_flush_v3(session) > 0) {
3816 			session->ns_mover.md_data_written += index;
3817 			session->ns_mover.md_record_num++;
3818 		}
3819 
3820 		if (n == 0)
3821 			ndmpd_mover_error(session,
3822 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
3823 		else
3824 			ndmpd_mover_error(session,
3825 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
3826 
3827 		return;
3828 	}
3829 
3830 	NDMP_LOG(LOG_DEBUG, "n %d", n);
3831 
3832 	session->ns_mover.md_w_index += n;
3833 
3834 	if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
3835 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3836 		    session->ns_mover.md_record_size);
3837 		if (n <= 0) {
3838 			ndmpd_mover_error(session,
3839 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3840 			    NDMP_MOVER_HALT_MEDIA_ERROR));
3841 			return;
3842 		}
3843 
3844 		session->ns_mover.md_position += n;
3845 		session->ns_mover.md_w_index = 0;
3846 		session->ns_mover.md_data_written += n;
3847 		session->ns_mover.md_record_num++;
3848 	}
3849 }
3850 
3851 /*
3852  * mover_tape_read_v3
3853  *
3854  * Reads a data record from tape. Detects and handles EOT conditions.
3855  *
3856  * Parameters:
3857  *   session (input) - session pointer.
3858  *   data    (input) - location to read data to.
3859  *
3860  * Returns:
3861  *   0 - operation aborted.
3862  *   TAPE_READ_ERR - tape read IO error.
3863  *   TAPE_NO_WRITER_ERR - no writer is running during tape read
3864  *   otherwise - number of bytes read.
3865  */
3866 static int
3867 mover_tape_read_v3(ndmpd_session_t *session, char *data)
3868 {
3869 	int pause_reason;
3870 	ssize_t	 n;
3871 	int err;
3872 	int count;
3873 
3874 	count = session->ns_mover.md_record_size;
3875 	while (count > 0) {
3876 		pause_reason = NDMP_MOVER_PAUSE_NA;
3877 
3878 		n = read(session->ns_tape.td_fd, data, count);
3879 		if (n < 0) {
3880 			/*
3881 			 * If at beginning of file and read fails with EIO,
3882 			 * then it's repeated attempt to read at EOT.
3883 			 */
3884 			if (errno == EIO && tape_is_at_bof(session)) {
3885 				NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
3886 				pause_reason = NDMP_MOVER_PAUSE_EOM;
3887 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3888 				    ++ndmp_log_msg_id,
3889 				    "End of tape reached. Load next tape");
3890 			}
3891 			/*
3892 			 * According to NDMPv4 spec preferred error code when
3893 			 * trying to read from blank tape is NDMP_EOM_ERR.
3894 			 */
3895 			else if (errno == EIO && tape_is_at_bot(session)) {
3896 				NDMP_LOG(LOG_ERR,
3897 				    "Blank tape detected, returning EOM");
3898 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3899 				    ++ndmp_log_msg_id,
3900 				    "Blank tape. Load another tape");
3901 				pause_reason = NDMP_MOVER_PAUSE_EOM;
3902 			} else {
3903 				NDMP_LOG(LOG_ERR, "Tape read error: %m.");
3904 				return (TAPE_READ_ERR);
3905 			}
3906 		} else if (n > 0) {
3907 			NS_ADD(rtape, n);
3908 			data += n;
3909 			count -= n;
3910 			session->ns_tape.td_record_count++;
3911 		} else {
3912 			if (!is_writer_running_v3(session))
3913 				return (TAPE_NO_WRITER_ERR);
3914 
3915 			/*
3916 			 * End of file or media reached. Notify client and
3917 			 * wait for the client to either abort the data
3918 			 * operation or continue the operation after changing
3919 			 * the tape.
3920 			 */
3921 			if (tape_is_at_bof(session)) {
3922 				NDMP_LOG(LOG_DEBUG, "EOT detected");
3923 				pause_reason = NDMP_MOVER_PAUSE_EOM;
3924 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3925 				    ++ndmp_log_msg_id, "End of medium reached");
3926 			} else {
3927 				NDMP_LOG(LOG_DEBUG, "EOF detected");
3928 				/* reposition the tape to BOT side of FM */
3929 				fm_dance(session);
3930 				pause_reason = NDMP_MOVER_PAUSE_EOF;
3931 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3932 				    ++ndmp_log_msg_id, "End of file reached.");
3933 			}
3934 		}
3935 
3936 		if (pause_reason != NDMP_MOVER_PAUSE_NA) {
3937 			err = mover_pause_v3(session, pause_reason);
3938 
3939 			/* Operation aborted or connection terminated? */
3940 			if (err < 0) {
3941 				return (0);
3942 			}
3943 			/* Retry the read from new location */
3944 		}
3945 	}
3946 	return (session->ns_mover.md_record_size);
3947 }
3948 
3949 
3950 /*
3951  * mover_data_write_v3
3952  *
3953  * Reads backup data from the tape device and writes the
3954  * data to the data connection.
3955  * This function is called by ndmpd_select when the data connection
3956  * is ready for more data to be written.
3957  *
3958  * Parameters:
3959  *   cookie  (input) - session pointer.
3960  *   fd      (input) - file descriptor.
3961  *   mode    (input) - select mode.
3962  *
3963  * Returns:
3964  *   void.
3965  */
3966 /*ARGSUSED*/
3967 static void
3968 mover_data_write_v3(void *cookie, int fd, ulong_t mode)
3969 {
3970 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3971 	int n;
3972 	ulong_t len;
3973 	u_longlong_t wlen;
3974 	ndmp_notify_mover_paused_request pause_request;
3975 
3976 	/*
3977 	 * If the end of the mover window has been reached,
3978 	 * then notify the client that a seek is needed.
3979 	 * Remove the file handler to prevent this function from
3980 	 * being called. The handler will be reinstalled in
3981 	 * ndmpd_mover_continue.
3982 	 */
3983 	if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
3984 	    + session->ns_mover.md_window_length) {
3985 		NDMP_LOG(LOG_DEBUG,
3986 		    "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
3987 
3988 		session->ns_mover.md_w_index = 0;
3989 		session->ns_mover.md_r_index = 0;
3990 
3991 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3992 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
3993 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
3994 		pause_request.seek_position =
3995 		    long_long_to_quad(session->ns_mover.md_position);
3996 		session->ns_mover.md_seek_position =
3997 		    session->ns_mover.md_position;
3998 
3999 		(void) ndmpd_remove_file_handler(session, fd);
4000 
4001 		if (ndmp_send_request(session->ns_connection,
4002 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
4003 		    (void *)&pause_request, 0) < 0) {
4004 			NDMP_LOG(LOG_DEBUG,
4005 			    "Sending notify_mover_paused request");
4006 			ndmpd_mover_error(session,
4007 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
4008 		}
4009 		return;
4010 	}
4011 
4012 	/*
4013 	 * Read more data into the tape buffer if the buffer is empty.
4014 	 */
4015 	if (session->ns_mover.md_w_index == 0) {
4016 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4017 
4018 		NDMP_LOG(LOG_DEBUG,
4019 		    "read %u bytes from tape", n);
4020 
4021 		if (n <= 0) {
4022 			ndmpd_mover_error(session, (n == 0 ?
4023 			    NDMP_MOVER_HALT_ABORTED
4024 			    : NDMP_MOVER_HALT_MEDIA_ERROR));
4025 			return;
4026 		}
4027 
4028 		/*
4029 		 * Discard data if the current data stream position is
4030 		 * prior to the seek position. This is necessary if a seek
4031 		 * request set the seek pointer to a position that is not a
4032 		 * record boundary. The seek request handler can only position
4033 		 * to the start of a record.
4034 		 */
4035 		if (session->ns_mover.md_position <
4036 		    session->ns_mover.md_seek_position) {
4037 			session->ns_mover.md_r_index =
4038 			    session->ns_mover.md_seek_position -
4039 			    session->ns_mover.md_position;
4040 			session->ns_mover.md_position =
4041 			    session->ns_mover.md_seek_position;
4042 		}
4043 
4044 		session->ns_mover.md_w_index = n;
4045 		session->ns_mover.md_record_num++;
4046 	}
4047 
4048 	/*
4049 	 * The limit on the total amount of data to be sent can be
4050 	 * dictated by either the end of the mover window or the end of the
4051 	 * seek window.
4052 	 * First determine which window applies and then determine if the
4053 	 * send length needs to be less than a full record to avoid
4054 	 * exceeding the window.
4055 	 */
4056 	if (session->ns_mover.md_position +
4057 	    session->ns_mover.md_bytes_left_to_read >
4058 	    session->ns_mover.md_window_offset +
4059 	    session->ns_mover.md_window_length)
4060 		wlen = session->ns_mover.md_window_offset +
4061 		    session->ns_mover.md_window_length -
4062 		    session->ns_mover.md_position;
4063 	else
4064 		wlen = session->ns_mover.md_bytes_left_to_read;
4065 
4066 	NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
4067 
4068 	/*
4069 	 * Now limit the length to the amount of data in the buffer.
4070 	 */
4071 	if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
4072 		wlen = session->ns_mover.md_w_index -
4073 		    session->ns_mover.md_r_index;
4074 
4075 	len = wlen & 0xffffffff;
4076 	NDMP_LOG(LOG_DEBUG,
4077 	    "buffer restrictions: wlen %llu len %u", wlen, len);
4078 
4079 	/*
4080 	 * Write the data to the data connection.
4081 	 */
4082 	n = write(session->ns_mover.md_sock,
4083 	    &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
4084 
4085 	if (n < 0) {
4086 		if (errno == EWOULDBLOCK) {
4087 			NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
4088 			return;
4089 		}
4090 
4091 		NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
4092 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
4093 		return;
4094 	}
4095 
4096 	NDMP_LOG(LOG_DEBUG,
4097 	    "wrote %u of %u bytes to data connection position %llu r_index %lu",
4098 	    n, len, session->ns_mover.md_position,
4099 	    session->ns_mover.md_r_index);
4100 
4101 	session->ns_mover.md_r_index += n;
4102 	session->ns_mover.md_position += n;
4103 	session->ns_mover.md_bytes_left_to_read -= n;
4104 
4105 	/*
4106 	 * If all data in the buffer has been written,
4107 	 * zero the buffer indices. The next call to this function
4108 	 * will read more data from the tape device into the buffer.
4109 	 */
4110 	if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
4111 		session->ns_mover.md_r_index = 0;
4112 		session->ns_mover.md_w_index = 0;
4113 	}
4114 
4115 	/*
4116 	 * If the read limit has been reached,
4117 	 * then remove the file handler to prevent this
4118 	 * function from getting called. The next mover_read request
4119 	 * will reinstall the handler.
4120 	 */
4121 	if (session->ns_mover.md_bytes_left_to_read == 0)
4122 		(void) ndmpd_remove_file_handler(session, fd);
4123 }
4124 
4125 
4126 /*
4127  * accept_connection_v3
4128  *
4129  * Accept a data connection from a data server.
4130  * Called by ndmpd_select when a connection is pending on
4131  * the mover listen socket.
4132  *
4133  * Parameters:
4134  *   cookie  (input) - session pointer.
4135  *   fd      (input) - file descriptor.
4136  *   mode    (input) - select mode.
4137  *
4138  * Returns:
4139  *   void.
4140  */
4141 /*ARGSUSED*/
4142 static void
4143 accept_connection_v3(void *cookie, int fd, ulong_t mode)
4144 {
4145 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
4146 	int from_len;
4147 	struct sockaddr_in from;
4148 	int flag = 1;
4149 
4150 	from_len = sizeof (from);
4151 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
4152 	    &from_len);
4153 
4154 	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
4155 	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
4156 
4157 	(void) ndmpd_remove_file_handler(session, fd);
4158 	(void) close(session->ns_mover.md_listen_sock);
4159 	session->ns_mover.md_listen_sock = -1;
4160 
4161 	if (session->ns_mover.md_sock < 0) {
4162 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
4163 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
4164 		return;
4165 	}
4166 
4167 	/*
4168 	 * Save the peer address.
4169 	 */
4170 	session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
4171 	session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
4172 
4173 	/*
4174 	 * Set the parameter of the new socket.
4175 	 */
4176 	(void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE,
4177 	    &flag, sizeof (flag));
4178 
4179 	ndmp_set_socket_nodelay(session->ns_mover.md_sock);
4180 	if (ndmp_sbs > 0)
4181 		ndmp_set_socket_snd_buf(session->ns_mover.md_sock,
4182 		    ndmp_sbs*KILOBYTE);
4183 	if (ndmp_rbs > 0)
4184 		ndmp_set_socket_rcv_buf(session->ns_mover.md_sock,
4185 		    ndmp_rbs*KILOBYTE);
4186 
4187 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
4188 
4189 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
4190 		if (ndmpd_add_file_handler(session, (void*)session,
4191 		    session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
4192 		    HC_MOVER, mover_data_read_v3) < 0) {
4193 			ndmpd_mover_error(session,
4194 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
4195 			return;
4196 		}
4197 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
4198 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4199 		    ntohs(from.sin_port));
4200 	} else {
4201 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
4202 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4203 		    ntohs(from.sin_port));
4204 	}
4205 
4206 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
4207 }
4208 
4209 
4210 /*
4211  * create_listen_socket_v3
4212  *
4213  * Creates a socket for listening for accepting data connections.
4214  *
4215  * Parameters:
4216  *   session (input)  - session pointer.
4217  *   addr    (output) - location to store address of socket.
4218  *   port    (output) - location to store port of socket.
4219  *
4220  * Returns:
4221  *   0 - success.
4222  *  -1 - error.
4223  */
4224 static int
4225 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
4226 {
4227 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
4228 	if (session->ns_mover.md_listen_sock < 0)
4229 		return (-1);
4230 
4231 	/*
4232 	 * Add a file handler for the listen socket.
4233 	 * ndmpd_select will call accept_connection when a
4234 	 * connection is ready to be accepted.
4235 	 */
4236 	if (ndmpd_add_file_handler(session, (void *) session,
4237 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
4238 	    accept_connection_v3) < 0) {
4239 		(void) close(session->ns_mover.md_listen_sock);
4240 		session->ns_mover.md_listen_sock = -1;
4241 		return (-1);
4242 	}
4243 	NDMP_LOG(LOG_DEBUG, "IP %s port %d",
4244 	    inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
4245 	return (0);
4246 }
4247 
4248 
4249 /*
4250  * mover_connect_sock_v3
4251  *
4252  * Connect the mover to the specified address
4253  *
4254  * Parameters:
4255  *   session (input)  - session pointer.
4256  *   mode    (input)  - mover mode.
4257  *   addr    (output) - location to store address of socket.
4258  *   port    (output) - location to store port of socket.
4259  *
4260  * Returns:
4261  *   error code.
4262  */
4263 static ndmp_error
4264 mover_connect_sock_v3(ndmpd_session_t *session, ndmp_mover_mode mode,
4265     ulong_t addr, ushort_t port)
4266 {
4267 	int sock;
4268 
4269 	sock = ndmp_connect_sock_v3(addr, port);
4270 	if (sock < 0)
4271 		return (NDMP_CONNECT_ERR);
4272 
4273 	if (mode == NDMP_MOVER_MODE_READ) {
4274 		if (ndmpd_add_file_handler(session, (void*)session, sock,
4275 		    NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
4276 			(void) close(sock);
4277 			return (NDMP_CONNECT_ERR);
4278 		}
4279 	}
4280 	session->ns_mover.md_sock = sock;
4281 	session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
4282 	session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
4283 	session->ns_mover.md_data_addr.tcp_port_v3 = port;
4284 	return (NDMP_NO_ERR);
4285 }
4286 
4287 
4288 /*
4289  * ndmpd_local_read_v3
4290  *
4291  * Reads data from the local tape device.
4292  * Full tape records are read and buffered.
4293  *
4294  * Parameters:
4295  *   session (input) - session pointer.
4296  *   data    (input) - location to store data.
4297  *   length  (input) - data length.
4298  *
4299  * Returns:
4300  *   1 - no read error but no writer running
4301  *   0 - data successfully read.
4302  *  -1 - error.
4303  */
4304 int
4305 ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
4306 {
4307 	ulong_t count;
4308 	ulong_t len;
4309 	ssize_t n;
4310 
4311 	count = 0;
4312 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
4313 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
4314 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
4315 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
4316 		return (-1);
4317 	}
4318 
4319 	/*
4320 	 * Automatically increase the seek window if necessary.
4321 	 * This is needed in the event the module attempts to read
4322 	 * past a seek window set via a prior call to ndmpd_seek() or
4323 	 * the module has not issued a seek. If no seek was issued then
4324 	 * pretend that a seek was issued to read the entire tape.
4325 	 */
4326 	if (length > session->ns_mover.md_bytes_left_to_read) {
4327 		/* ndmpd_seek() never called? */
4328 		if (session->ns_data.dd_read_length == 0) {
4329 			session->ns_mover.md_bytes_left_to_read = ~0LL;
4330 			session->ns_data.dd_read_offset = 0LL;
4331 			session->ns_data.dd_read_length = ~0LL;
4332 		} else {
4333 			session->ns_mover.md_bytes_left_to_read = length;
4334 			session->ns_data.dd_read_offset =
4335 			    session->ns_mover.md_position;
4336 			session->ns_data.dd_read_length = length;
4337 		}
4338 	}
4339 
4340 	/*
4341 	 * Read as many records as necessary to satisfy the request.
4342 	 */
4343 	while (count < length) {
4344 		/*
4345 		 * If the end of the mover window has been reached,
4346 		 * then notify the client that a new data window is needed.
4347 		 */
4348 		if (session->ns_mover.md_position >=
4349 		    session->ns_mover.md_window_offset +
4350 		    session->ns_mover.md_window_length) {
4351 			if (mover_pause_v3(session,
4352 			    NDMP_MOVER_PAUSE_SEEK) < 0) {
4353 				ndmpd_mover_error(session,
4354 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
4355 				return (-1);
4356 			}
4357 			continue;
4358 		}
4359 
4360 		len = length - count;
4361 
4362 		/*
4363 		 * Prevent reading past the end of the window.
4364 		 */
4365 		if (len > session->ns_mover.md_window_offset +
4366 		    session->ns_mover.md_window_length -
4367 		    session->ns_mover.md_position)
4368 			len = session->ns_mover.md_window_offset +
4369 			    session->ns_mover.md_window_length -
4370 			    session->ns_mover.md_position;
4371 
4372 		/*
4373 		 * Copy from the data buffer first.
4374 		 */
4375 		if (session->ns_mover.md_w_index -
4376 		    session->ns_mover.md_r_index != 0) {
4377 			/*
4378 			 * Limit the copy to the amount of data in the buffer.
4379 			 */
4380 			if (len > session->ns_mover.md_w_index -
4381 			    session->ns_mover.md_r_index)
4382 				len = session->ns_mover.md_w_index -
4383 				    session->ns_mover.md_r_index;
4384 			(void) memcpy((void*)&data[count],
4385 			    &session->ns_mover.md_buf[session->
4386 			    ns_mover.md_r_index], len);
4387 			count += len;
4388 			session->ns_mover.md_r_index += len;
4389 			session->ns_mover.md_bytes_left_to_read -= len;
4390 			session->ns_mover.md_position += len;
4391 			continue;
4392 		}
4393 
4394 		/*
4395 		 * Determine if data needs to be buffered or
4396 		 * can be read directly to user supplied location.
4397 		 * We can fast path the read if at least a full record
4398 		 * needs to be read and there is no seek pending.
4399 		 * This is done to eliminate a buffer copy.
4400 		 */
4401 		if (len >= session->ns_mover.md_record_size &&
4402 		    session->ns_mover.md_position >=
4403 		    session->ns_mover.md_seek_position) {
4404 			n = mover_tape_read_v3(session, &data[count]);
4405 			if (n <= 0) {
4406 				if (n == TAPE_NO_WRITER_ERR)
4407 					return (1);
4408 
4409 				ndmpd_mover_error(session,
4410 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4411 				    NDMP_MOVER_HALT_MEDIA_ERROR));
4412 				return ((n == 0) ? 1 : -1);
4413 			}
4414 
4415 			count += n;
4416 			session->ns_mover.md_bytes_left_to_read -= n;
4417 			session->ns_mover.md_position += n;
4418 			session->ns_mover.md_record_num++;
4419 			continue;
4420 		}
4421 
4422 		/* Read the next record into the buffer. */
4423 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4424 		if (n <= 0) {
4425 			if (n == TAPE_NO_WRITER_ERR)
4426 				return (1);
4427 
4428 			ndmpd_mover_error(session,
4429 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4430 			    NDMP_MOVER_HALT_MEDIA_ERROR));
4431 			return ((n == 0) ? 1 : -1);
4432 		}
4433 
4434 		session->ns_mover.md_w_index = n;
4435 		session->ns_mover.md_r_index = 0;
4436 		session->ns_mover.md_record_num++;
4437 
4438 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
4439 
4440 		/*
4441 		 * Discard data if the current data stream position is
4442 		 * prior to the seek position. This is necessary if a seek
4443 		 * request set the seek pointer to a position that is not a
4444 		 * record boundary. The seek request handler can only position
4445 		 * to the start of a record.
4446 		 */
4447 		if (session->ns_mover.md_position <
4448 		    session->ns_mover.md_seek_position) {
4449 			session->ns_mover.md_r_index =
4450 			    session->ns_mover.md_seek_position -
4451 			    session->ns_mover.md_position;
4452 			session->ns_mover.md_position =
4453 			    session->ns_mover.md_seek_position;
4454 		}
4455 	}
4456 
4457 	return (0);
4458 }
4459