xref: /titanic_44/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c (revision 98d1cbfec254295273b6a761bc1861c0374bdf02)
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 
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <net/if.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <netdb.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include "ndmpd_common.h"
55 #include "ndmpd.h"
56 #include <sys/mtio.h>
57 
58 /*
59  * Maximum mover record size
60  */
61 #define	MAX_MOVER_RECSIZE	(512*KILOBYTE)
62 
63 static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
64     ushort_t *port);
65 static int tape_write(ndmpd_session_t *session, char *data, ssize_t length);
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_write_eom
1358  *
1359  * Write end-of-media magic string.  This is called after hitting the LEOT.
1360  */
1361 void
1362 ndmpd_write_eom(int fd)
1363 {
1364 	int n;
1365 
1366 	(void) ndmp_mtioctl(fd, MTWEOF, 1);
1367 	n = write(fd, NDMP_EOM_MAGIC, strlen(NDMP_EOM_MAGIC));
1368 
1369 	NDMP_LOG(LOG_DEBUG, "%d EOM bytes wrote", n);
1370 	(void) ndmp_mtioctl(fd, MTWEOF, 1);
1371 
1372 	/*
1373 	 * Rewind to the previous file since the last two files are used
1374 	 * as the indicator for logical EOM.
1375 	 */
1376 	(void) ndmp_mtioctl(fd, MTBSF, 2);
1377 }
1378 
1379 
1380 /*
1381  * ndmpd_local_write
1382  *
1383  * Writes data to the mover.
1384  * Buffers and write data to the tape device.
1385  * A full tape record is buffered before being written.
1386  *
1387  * Parameters:
1388  *   session    (input) - session pointer.
1389  *   data       (input) - data to be written.
1390  *   length     (input) - data length.
1391  *
1392  * Returns:
1393  *   0 - data successfully written.
1394  *  -1 - error.
1395  */
1396 int
1397 ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
1398 {
1399 	ulong_t count = 0;
1400 	ssize_t n;
1401 	ulong_t len;
1402 
1403 	/*
1404 	 * A length of 0 indicates that any buffered data should be
1405 	 * flushed to tape.
1406 	 */
1407 	if (length == 0) {
1408 		if (session->ns_mover.md_w_index == 0)
1409 			return (0);
1410 
1411 		(void) memset(
1412 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1413 		    0, session->ns_mover.md_record_size -
1414 		    session->ns_mover.md_w_index);
1415 
1416 		n = tape_write(session, session->ns_mover.md_buf,
1417 		    session->ns_mover.md_record_size);
1418 		if (n <= 0) {
1419 			ndmpd_mover_error(session,
1420 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1421 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
1422 			return (-1);
1423 		}
1424 		session->ns_mover.md_position += n;
1425 		session->ns_mover.md_data_written +=
1426 		    session->ns_mover.md_w_index;
1427 		session->ns_mover.md_record_num++;
1428 		session->ns_mover.md_w_index = 0;
1429 		return (0);
1430 	}
1431 	/* Break the data into records. */
1432 	while (count < length) {
1433 		/*
1434 		 * Determine if data needs to be buffered or
1435 		 * can be written directly from user supplied location.
1436 		 * We can fast path the write if there is no pending
1437 		 * buffered data and there is at least a full record's worth
1438 		 * of data to be written.
1439 		 */
1440 		if (session->ns_mover.md_w_index == 0 &&
1441 		    length - count >= session->ns_mover.md_record_size) {
1442 			n = tape_write(session, &data[count],
1443 			    session->ns_mover.md_record_size);
1444 			if (n <= 0) {
1445 				ndmpd_mover_error(session,
1446 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1447 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1448 				return (-1);
1449 			}
1450 			session->ns_mover.md_position += n;
1451 			session->ns_mover.md_data_written += n;
1452 			session->ns_mover.md_record_num++;
1453 			count += n;
1454 			continue;
1455 		}
1456 		/* Buffer the data */
1457 		len = length - count;
1458 		if (len > session->ns_mover.md_record_size -
1459 		    session->ns_mover.md_w_index)
1460 			len = session->ns_mover.md_record_size -
1461 			    session->ns_mover.md_w_index;
1462 
1463 		(void) memcpy(
1464 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1465 		    &data[count], len);
1466 		session->ns_mover.md_w_index += len;
1467 		count += len;
1468 
1469 		/* Write the buffer if its full */
1470 		if (session->ns_mover.md_w_index ==
1471 		    session->ns_mover.md_record_size) {
1472 			n = tape_write(session, session->ns_mover.md_buf,
1473 			    session->ns_mover.md_record_size);
1474 			if (n < 0) {
1475 				ndmpd_mover_error(session,
1476 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1477 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1478 				return (-1);
1479 			}
1480 			session->ns_mover.md_position += n;
1481 			session->ns_mover.md_data_written += n;
1482 			session->ns_mover.md_record_num++;
1483 			session->ns_mover.md_w_index = 0;
1484 		}
1485 	}
1486 
1487 	return (0);
1488 }
1489 
1490 
1491 /*
1492  * ndmpd_remote_write
1493  *
1494  * Writes data to the remote mover.
1495  *
1496  * Parameters:
1497  *   session    (input) - session pointer.
1498  *   data       (input) - data to be written.
1499  *   length     (input) - data length.
1500  *
1501  * Returns:
1502  *   0 - data successfully written.
1503  *  -1 - error.
1504  */
1505 int
1506 ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
1507 {
1508 	ssize_t n;
1509 	ulong_t count = 0;
1510 
1511 	while (count < length) {
1512 		if (session->ns_eof == TRUE ||
1513 		    session->ns_data.dd_abort == TRUE)
1514 			return (-1);
1515 
1516 		if ((n = write(session->ns_data.dd_sock, &data[count],
1517 		    length - count)) < 0) {
1518 			NDMP_LOG(LOG_ERR, "Socket write error: %m.");
1519 			return (-1);
1520 		}
1521 		count += n;
1522 	}
1523 
1524 	return (0);
1525 }
1526 
1527 /*
1528  * ndmpd_local_read
1529  *
1530  * Reads data from the local tape device.
1531  * Full tape records are read and buffered.
1532  *
1533  * Parameters:
1534  *   session (input) - session pointer.
1535  *   data    (input) - location to store data.
1536  *   length  (input) - data length.
1537  *
1538  * Returns:
1539  *   0 - data successfully read.
1540  *  -1 - error.
1541  *   1 - session terminated or operation aborted.
1542  */
1543 int
1544 ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
1545 {
1546 	ulong_t count = 0;
1547 	ssize_t n;
1548 	ulong_t len;
1549 	ndmp_notify_mover_paused_request pause_request;
1550 
1551 	/*
1552 	 * Automatically increase the seek window if necessary.
1553 	 * This is needed in the event the module attempts to read
1554 	 * past a seek window set via a prior call to ndmpd_seek() or
1555 	 * the module has not issued a seek. If no seek was issued then
1556 	 * pretend that a seek was issued to read the entire tape.
1557 	 */
1558 	if (length > session->ns_mover.md_bytes_left_to_read) {
1559 		/* ndmpd_seek() never called? */
1560 		if (session->ns_data.dd_read_length == 0) {
1561 			session->ns_mover.md_bytes_left_to_read = ~0LL;
1562 			session->ns_data.dd_read_offset = 0LL;
1563 			session->ns_data.dd_read_length = ~0LL;
1564 		} else {
1565 			session->ns_mover.md_bytes_left_to_read = length;
1566 			session->ns_data.dd_read_offset =
1567 			    session->ns_mover.md_position;
1568 			session->ns_data.dd_read_length = length;
1569 		}
1570 	}
1571 	/*
1572 	 * Read as many records as necessary to satisfy the request.
1573 	 */
1574 	while (count < length) {
1575 		/*
1576 		 * If the end of the mover window has been reached,
1577 		 * then notify the client that a new data window is needed.
1578 		 */
1579 		if (session->ns_mover.md_position >=
1580 		    session->ns_mover.md_window_offset +
1581 		    session->ns_mover.md_window_length) {
1582 
1583 			session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
1584 			session->ns_mover.md_pause_reason =
1585 			    NDMP_MOVER_PAUSE_SEEK;
1586 			pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
1587 			pause_request.seek_position =
1588 			    long_long_to_quad(session->ns_mover.md_position);
1589 
1590 			if (ndmp_send_request(session->ns_connection,
1591 			    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
1592 			    (void *) &pause_request, 0) < 0) {
1593 				NDMP_LOG(LOG_DEBUG,
1594 				    "Sending notify_mover_paused request");
1595 				ndmpd_mover_error(session,
1596 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
1597 				return (-1);
1598 			}
1599 			/*
1600 			 * Wait until the state is changed by
1601 			 * an abort or continue request.
1602 			 */
1603 			nlp_ref_nw(session);
1604 			for (; ; ) {
1605 				nlp_wait_nw(session);
1606 
1607 				if (session->ns_eof == TRUE) {
1608 					nlp_unref_nw(session);
1609 					return (1);
1610 				}
1611 
1612 				switch (session->ns_mover.md_state) {
1613 				case NDMP_MOVER_STATE_ACTIVE:
1614 					break;
1615 
1616 				case NDMP_MOVER_STATE_PAUSED:
1617 					continue;
1618 
1619 				default:
1620 					nlp_unref_nw(session);
1621 					return (-1);
1622 				}
1623 			}
1624 		}
1625 		len = length - count;
1626 
1627 		/*
1628 		 * Prevent reading past the end of the window.
1629 		 */
1630 		if (len >
1631 		    session->ns_mover.md_window_offset +
1632 		    session->ns_mover.md_window_length -
1633 		    session->ns_mover.md_position)
1634 			len = session->ns_mover.md_window_offset +
1635 			    session->ns_mover.md_window_length -
1636 			    session->ns_mover.md_position;
1637 
1638 		/*
1639 		 * Copy from the data buffer first.
1640 		 */
1641 		if (session->ns_mover.md_w_index -
1642 		    session->ns_mover.md_r_index != 0) {
1643 			/*
1644 			 * Limit the copy to the amount of data in the buffer.
1645 			 */
1646 			if (len > session->ns_mover.md_w_index -
1647 			    session->ns_mover.md_r_index)
1648 				len = session->ns_mover.md_w_index
1649 				    - session->ns_mover.md_r_index;
1650 
1651 			(void) memcpy((void *) &data[count],
1652 			    &session->ns_mover.md_buf[session->
1653 			    ns_mover.md_r_index], len);
1654 			count += len;
1655 			session->ns_mover.md_r_index += len;
1656 			session->ns_mover.md_bytes_left_to_read -= len;
1657 			session->ns_mover.md_position += len;
1658 			continue;
1659 		}
1660 		/*
1661 		 * Determine if data needs to be buffered or
1662 		 * can be read directly to user supplied location.
1663 		 * We can fast path the read if at least a full record
1664 		 * needs to be read and there is no seek pending.
1665 		 * This is done to eliminate a buffer copy.
1666 		 */
1667 		if (len >= session->ns_mover.md_record_size &&
1668 		    session->ns_mover.md_position >=
1669 		    session->ns_mover.md_seek_position) {
1670 			n = tape_read(session, &data[count]);
1671 			if (n <= 0) {
1672 				if (n == TAPE_NO_WRITER_ERR)
1673 					return (1);
1674 
1675 				ndmpd_mover_error(session,
1676 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1677 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1678 				return (n == 0) ? (1) : (-1);
1679 			}
1680 			count += n;
1681 			session->ns_mover.md_bytes_left_to_read -= n;
1682 			session->ns_mover.md_position += n;
1683 			continue;
1684 		}
1685 		/* Read the next record into the buffer. */
1686 		n = tape_read(session, session->ns_mover.md_buf);
1687 		if (n <= 0) {
1688 			if (n == TAPE_NO_WRITER_ERR)
1689 				return (1);
1690 
1691 			ndmpd_mover_error(session,
1692 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1693 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
1694 			return (n == 0) ? (1) : (-1);
1695 		}
1696 		session->ns_mover.md_w_index = n;
1697 		session->ns_mover.md_r_index = 0;
1698 
1699 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
1700 
1701 		/*
1702 		 * Discard data if the current data stream position is
1703 		 * prior to the seek position. This is necessary if a seek
1704 		 * request set the seek pointer to a position that is not a
1705 		 * record boundary. The seek request handler can only position
1706 		 * to the start of a record.
1707 		 */
1708 		if (session->ns_mover.md_position <
1709 		    session->ns_mover.md_seek_position) {
1710 			session->ns_mover.md_r_index =
1711 			    session->ns_mover.md_seek_position -
1712 			    session->ns_mover.md_position;
1713 			session->ns_mover.md_position =
1714 			    session->ns_mover.md_seek_position;
1715 		}
1716 	}
1717 
1718 	return (0);
1719 }
1720 
1721 
1722 /*
1723  * ndmpd_remote_read
1724  *
1725  * Reads data from the remote mover.
1726  *
1727  * Parameters:
1728  *   session (input) - session pointer.
1729  *   data    (input) - data to be written.
1730  *   length  (input) - data length.
1731  *
1732  * Returns:
1733  *   0 - data successfully read.
1734  *  -1 - error.
1735  *   1 - session terminated or operation aborted.
1736  */
1737 int
1738 ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
1739 {
1740 	ulong_t count = 0;
1741 	ssize_t n;
1742 	ulong_t len;
1743 	ndmp_notify_data_read_request request;
1744 
1745 	while (count < length) {
1746 		len = length - count;
1747 
1748 		/*
1749 		 * If the end of the seek window has been reached then
1750 		 * send an ndmp_read request to the client.
1751 		 * The NDMP client will then send a mover_data_read request to
1752 		 * the remote mover and the mover will send more data.
1753 		 * This condition can occur if the module attempts to read past
1754 		 * a seek window set via a prior call to ndmpd_seek() or
1755 		 * the module has not issued a seek. If no seek was issued then
1756 		 * pretend that a seek was issued to read the entire tape.
1757 		 */
1758 		if (session->ns_mover.md_bytes_left_to_read == 0) {
1759 			/* ndmpd_seek() never called? */
1760 			if (session->ns_data.dd_read_length == 0) {
1761 				session->ns_mover.md_bytes_left_to_read = ~0LL;
1762 				session->ns_data.dd_read_offset = 0LL;
1763 				session->ns_data.dd_read_length = ~0LL;
1764 			} else {
1765 				session->ns_mover.md_bytes_left_to_read = len;
1766 				session->ns_data.dd_read_offset =
1767 				    session->ns_mover.md_position;
1768 				session->ns_data.dd_read_length = len;
1769 			}
1770 
1771 			request.offset =
1772 			    long_long_to_quad(session->ns_data.dd_read_offset);
1773 			request.length =
1774 			    long_long_to_quad(session->ns_data.dd_read_length);
1775 
1776 			if (ndmp_send_request_lock(session->ns_connection,
1777 			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1778 			    (void *) &request, 0) < 0) {
1779 				NDMP_LOG(LOG_DEBUG,
1780 				    "Sending notify_data_read request");
1781 				return (-1);
1782 			}
1783 		}
1784 		if (session->ns_eof == TRUE ||
1785 		    session->ns_data.dd_abort == TRUE)
1786 			return (1);
1787 
1788 		/*
1789 		 * If the module called ndmpd_seek() prior to reading all of the
1790 		 * data that the remote mover was requested to send, then the
1791 		 * excess data from the seek has to be discardd.
1792 		 */
1793 		if (session->ns_mover.md_discard_length != 0) {
1794 			n = discard_data(session,
1795 			    (ulong_t)session->ns_mover.md_discard_length);
1796 			if (n < 0)
1797 				return (-1);
1798 			session->ns_mover.md_discard_length -= n;
1799 			continue;
1800 		}
1801 		/*
1802 		 * Don't attempt to read more data than the remote is sending.
1803 		 */
1804 		if (len > session->ns_mover.md_bytes_left_to_read)
1805 			len = session->ns_mover.md_bytes_left_to_read;
1806 
1807 		NDMP_LOG(LOG_DEBUG, "len: %u", len);
1808 
1809 		if ((n = read(session->ns_data.dd_sock, &data[count],
1810 		    len)) < 0) {
1811 			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1812 			return (-1);
1813 		}
1814 		/* read returns 0 if the connection was closed */
1815 		if (n == 0)
1816 			return (-1);
1817 
1818 		count += n;
1819 		session->ns_mover.md_bytes_left_to_read -= n;
1820 		session->ns_mover.md_position += n;
1821 	}
1822 
1823 	return (0);
1824 }
1825 
1826 /* *** ndmpd internal functions ***************************************** */
1827 
1828 /*
1829  * ndmpd_mover_init
1830  *
1831  * Initialize mover specific session variables.
1832  * Don't initialize variables such as record_size that need to
1833  * persist across data operations. A client may open a connection and
1834  * do multiple backups after setting the record_size.
1835  *
1836  * Parameters:
1837  *   session (input) - session pointer.
1838  *
1839  * Returns:
1840  *   0 - success.
1841  *  -1 - error.
1842  */
1843 int
1844 ndmpd_mover_init(ndmpd_session_t *session)
1845 {
1846 	session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
1847 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
1848 	session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
1849 	session->ns_mover.md_data_written = 0LL;
1850 	session->ns_mover.md_seek_position = 0LL;
1851 	session->ns_mover.md_bytes_left_to_read = 0LL;
1852 	session->ns_mover.md_window_offset = 0LL;
1853 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
1854 	session->ns_mover.md_position = 0LL;
1855 	session->ns_mover.md_discard_length = 0;
1856 	session->ns_mover.md_record_num = 0;
1857 	session->ns_mover.md_record_size = 0;
1858 	session->ns_mover.md_listen_sock = -1;
1859 	session->ns_mover.md_pre_cond = FALSE;
1860 	session->ns_mover.md_sock = -1;
1861 	session->ns_mover.md_r_index = 0;
1862 	session->ns_mover.md_w_index = 0;
1863 	session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
1864 	if (!session->ns_mover.md_buf)
1865 		return (-1);
1866 
1867 	if (ndmp_get_version(session->ns_connection) == NDMPV3) {
1868 		session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
1869 		(void) memset(&session->ns_mover.md_data_addr, 0,
1870 		    sizeof (ndmp_addr_v3));
1871 	}
1872 	return (0);
1873 }
1874 
1875 
1876 /*
1877  * ndmpd_mover_shut_down
1878  *
1879  * Shutdown the mover. It closes all the sockets.
1880  *
1881  * Parameters:
1882  *   session (input) - session pointer.
1883  *
1884  * Returns:
1885  *   void
1886  */
1887 void
1888 ndmpd_mover_shut_down(ndmpd_session_t *session)
1889 {
1890 	if (session->ns_mover.md_listen_sock != -1) {
1891 		NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
1892 		    session->ns_mover.md_listen_sock);
1893 		(void) ndmpd_remove_file_handler(session,
1894 		    session->ns_mover.md_listen_sock);
1895 		(void) close(session->ns_mover.md_listen_sock);
1896 		session->ns_mover.md_listen_sock = -1;
1897 	}
1898 	if (session->ns_mover.md_sock != -1) {
1899 		NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
1900 		    session->ns_mover.md_sock);
1901 		(void) ndmpd_remove_file_handler(session,
1902 		    session->ns_mover.md_sock);
1903 		(void) close(session->ns_mover.md_sock);
1904 		session->ns_mover.md_sock = -1;
1905 	}
1906 }
1907 
1908 
1909 /*
1910  * ndmpd_mover_cleanup
1911  *
1912  * Parameters:
1913  *   session (input) - session pointer.
1914  *
1915  * Returns:
1916  *   void
1917  */
1918 void
1919 ndmpd_mover_cleanup(ndmpd_session_t *session)
1920 {
1921 	NDMP_FREE(session->ns_mover.md_buf);
1922 }
1923 
1924 
1925 /*
1926  * ndmpd_mover_connect
1927  *   Create a connection to the specified mover.
1928  *
1929  * Parameters:
1930  *   session (input) - session pointer
1931  *
1932  * Returns:
1933  *   error code.
1934  */
1935 ndmp_error
1936 ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
1937 {
1938 	ndmp_mover_addr *mover = &session->ns_data.dd_mover;
1939 	struct sockaddr_in sin;
1940 	int sock = -1;
1941 	int flag = 1;
1942 
1943 	if (mover->addr_type == NDMP_ADDR_TCP) {
1944 		if (mover->ndmp_mover_addr_u.addr.ip_addr) {
1945 			(void) memset((void *) &sin, 0, sizeof (sin));
1946 			sin.sin_family = AF_INET;
1947 			sin.sin_addr.s_addr =
1948 			    htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
1949 			sin.sin_port =
1950 			    htons(mover->ndmp_mover_addr_u.addr.port);
1951 
1952 			/*
1953 			 * If the address type is TCP but both the address and
1954 			 * the port number are zero, we have to use a different
1955 			 * socket than the mover socket. This can happen when
1956 			 * using NDMP disk to disk copy (AKA D2D copy).
1957 			 * The NDMPCopy client will send a zero address to
1958 			 * direct the server to use the mover socket as the
1959 			 * data socket to receive the recovery data.
1960 			 */
1961 			if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
1962 				session->ns_data.dd_sock =
1963 				    session->ns_mover.md_sock;
1964 				return (NDMP_NO_ERR);
1965 			}
1966 
1967 			NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
1968 			    mover->ndmp_mover_addr_u.addr.ip_addr,
1969 			    (ulong_t)sin.sin_port);
1970 
1971 			if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1972 				NDMP_LOG(LOG_DEBUG, "Socket error: %m");
1973 				return (NDMP_IO_ERR);
1974 			}
1975 			if (connect(sock, (struct sockaddr *)&sin,
1976 			    sizeof (sin)) < 0) {
1977 				NDMP_LOG(LOG_DEBUG, "Connect error: %m");
1978 				(void) close(sock);
1979 				return (NDMP_IO_ERR);
1980 			}
1981 
1982 			if (ndmp_sbs > 0)
1983 				ndmp_set_socket_snd_buf(sock,
1984 				    ndmp_sbs * KILOBYTE);
1985 			if (ndmp_rbs > 0)
1986 				ndmp_set_socket_rcv_buf(sock,
1987 				    ndmp_rbs * KILOBYTE);
1988 
1989 			ndmp_set_socket_nodelay(sock);
1990 			(void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag,
1991 			    sizeof (flag));
1992 		} else {
1993 			if ((session->ns_mover.md_state !=
1994 			    NDMP_MOVER_STATE_ACTIVE) ||
1995 			    (session->ns_mover.md_sock == -1)) {
1996 
1997 				NDMP_LOG(LOG_DEBUG,
1998 				    "Not in active  state mover"
1999 				    "  state = %d or Invalid mover sock=%d",
2000 				    session->ns_mover.md_state,
2001 				    session->ns_mover.md_sock);
2002 				return (NDMP_ILLEGAL_STATE_ERR);
2003 			}
2004 
2005 			sock = session->ns_mover.md_sock;
2006 			NDMP_LOG(LOG_DEBUG,
2007 			    "session: 0x%x setting data sock fd: %d to be"
2008 			    " same as listen_sock", session, sock);
2009 		}
2010 
2011 		NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
2012 
2013 		session->ns_data.dd_sock = sock;
2014 
2015 		NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
2016 
2017 		return (NDMP_NO_ERR);
2018 	}
2019 	/* Local mover connection. */
2020 
2021 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
2022 		NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
2023 		return (NDMP_ILLEGAL_STATE_ERR);
2024 	}
2025 	if (session->ns_tape.td_fd == -1) {
2026 		NDMP_LOG(LOG_DEBUG, "Tape device not open");
2027 		return (NDMP_DEV_NOT_OPEN_ERR);
2028 	}
2029 	if (mover_mode == NDMP_MOVER_MODE_READ &&
2030 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
2031 		NDMP_LOG(LOG_ERR, "Write protected device.");
2032 		return (NDMP_WRITE_PROTECT_ERR);
2033 	}
2034 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2035 	session->ns_mover.md_mode = mover_mode;
2036 
2037 	return (NDMP_NO_ERR);
2038 }
2039 
2040 
2041 
2042 /*
2043  * ndmpd_mover_seek
2044  *
2045  * Seek to the requested data stream position.
2046  * If the requested offset is outside of the current window,
2047  * the mover is paused and a notify_mover_paused request is sent
2048  * notifying the client that a seek is required.
2049  * If the requested offest is within the window but not within the
2050  * current record, then the tape is positioned to the record containing
2051  * the requested offest.
2052  * The requested amount of data is then read from the tape device and
2053  * written to the data connection.
2054  *
2055  * Parameters:
2056  *   session (input) - session pointer.
2057  *   offset  (input) - data stream position to seek to.
2058  *   length  (input) - amount of data that will be read.
2059  *
2060  * Returns:
2061  *   1 - seek pending completion by the NDMP client.
2062  *   0 - seek successfully completed.
2063  *  -1 - error.
2064  */
2065 int
2066 ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
2067     u_longlong_t length)
2068 {
2069 	int ctlcmd;
2070 	int ctlcnt;
2071 	u_longlong_t tape_position;
2072 	u_longlong_t buf_position;
2073 	ndmp_notify_mover_paused_request pause_request;
2074 
2075 	session->ns_mover.md_seek_position = offset;
2076 	session->ns_mover.md_bytes_left_to_read = length;
2077 
2078 	/*
2079 	 * If the requested position is outside of the window,
2080 	 * notify the client that a seek is required.
2081 	 */
2082 	if (session->ns_mover.md_seek_position <
2083 	    session->ns_mover.md_window_offset ||
2084 	    session->ns_mover.md_seek_position >=
2085 	    session->ns_mover.md_window_offset +
2086 	    session->ns_mover.md_window_length) {
2087 		NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
2088 		    session->ns_mover.md_seek_position);
2089 
2090 		session->ns_mover.md_w_index = 0;
2091 		session->ns_mover.md_r_index = 0;
2092 
2093 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2094 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2095 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2096 		pause_request.seek_position = long_long_to_quad(offset);
2097 
2098 		if (ndmp_send_request(session->ns_connection,
2099 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2100 		    (void *) &pause_request, 0) < 0) {
2101 			NDMP_LOG(LOG_DEBUG,
2102 			    "Sending notify_mover_paused request");
2103 			return (-1);
2104 		}
2105 		return (1);
2106 	}
2107 	/*
2108 	 * Determine the data stream position of the first byte in the
2109 	 * data buffer.
2110 	 */
2111 	buf_position = session->ns_mover.md_position -
2112 	    (session->ns_mover.md_position % session->ns_mover.md_record_size);
2113 
2114 	/*
2115 	 * Determine the data stream position of the next byte that
2116 	 * will be read from tape.
2117 	 */
2118 	tape_position = buf_position;
2119 	if (session->ns_mover.md_w_index != 0)
2120 		tape_position += session->ns_mover.md_record_size;
2121 
2122 	/*
2123 	 * Check if requested position is for data that has been read and is
2124 	 * in the buffer.
2125 	 */
2126 	if (offset >= buf_position && offset < tape_position) {
2127 		session->ns_mover.md_position = offset;
2128 		session->ns_mover.md_r_index = session->ns_mover.md_position -
2129 		    buf_position;
2130 
2131 		NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
2132 		    session->ns_mover.md_position,
2133 		    session->ns_mover.md_r_index);
2134 
2135 		return (0);
2136 	}
2137 
2138 	ctlcmd = 0;
2139 	if (tape_position > session->ns_mover.md_seek_position) {
2140 		/* Need to seek backward. */
2141 		ctlcmd = MTBSR;
2142 		ctlcnt = (int)((tape_position - offset - 1)
2143 		    / session->ns_mover.md_record_size) + 1;
2144 		tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
2145 		    session->ns_mover.md_record_size) + 1) *
2146 		    (u_longlong_t)session->ns_mover.md_record_size);
2147 
2148 	} else if (offset >= tape_position + session->ns_mover.md_record_size) {
2149 		/* Need to seek forward. */
2150 		ctlcmd = MTFSR;
2151 		ctlcnt = (int)((offset - tape_position)
2152 		    / session->ns_mover.md_record_size);
2153 		tape_position += ((u_longlong_t)(((offset - tape_position) /
2154 		    session->ns_mover.md_record_size)) *
2155 		    (u_longlong_t)session->ns_mover.md_record_size);
2156 	}
2157 	/* Reposition the tape if necessary. */
2158 	if (ctlcmd) {
2159 		NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
2160 		    ctlcmd, ctlcnt);
2161 		(void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
2162 	}
2163 
2164 	session->ns_mover.md_position = tape_position;
2165 	session->ns_mover.md_r_index = 0;
2166 	session->ns_mover.md_w_index = 0;
2167 
2168 	NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
2169 
2170 	return (0);
2171 }
2172 
2173 
2174 /* ** static functions ************************************************** */
2175 
2176 /*
2177  * create_listen_socket_v2
2178  *
2179  * Creates a socket for listening for accepting data connections.
2180  *
2181  * Parameters:
2182  *   session (input)  - session pointer.
2183  *   addr    (output) - location to store address of socket.
2184  *   port    (output) - location to store port of socket.
2185  *
2186  * Returns:
2187  *   0 - success.
2188  *  -1 - error.
2189  */
2190 static int
2191 create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
2192 {
2193 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
2194 	if (session->ns_mover.md_listen_sock < 0)
2195 		return (-1);
2196 
2197 	/*
2198 	 * Add a file handler for the listen socket.
2199 	 * ndmpd_select will call accept_connection when a
2200 	 * connection is ready to be accepted.
2201 	 */
2202 	if (ndmpd_add_file_handler(session, (void *) session,
2203 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
2204 	    accept_connection) < 0) {
2205 		(void) close(session->ns_mover.md_listen_sock);
2206 		session->ns_mover.md_listen_sock = -1;
2207 		return (-1);
2208 	}
2209 
2210 	NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
2211 	return (0);
2212 }
2213 
2214 
2215 /*
2216  * accept_connection
2217  *
2218  * Accept a data connection from a data server.
2219  * Called by ndmpd_select when a connection is pending on
2220  * the mover listen socket.
2221  *
2222  * Parameters:
2223  *   cookie  (input) - session pointer.
2224  *   fd      (input) - file descriptor.
2225  *   mode    (input) - select mode.
2226  *
2227  * Returns:
2228  *   void.
2229  */
2230 /*ARGSUSED*/
2231 static void
2232 accept_connection(void *cookie, int fd, ulong_t mode)
2233 {
2234 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
2235 	struct sockaddr_in from;
2236 	int from_len;
2237 	int flag = 1;
2238 
2239 	from_len = sizeof (from);
2240 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
2241 	    &from_len);
2242 
2243 	(void) ndmpd_remove_file_handler(session, fd);
2244 	(void) close(session->ns_mover.md_listen_sock);
2245 	session->ns_mover.md_listen_sock = -1;
2246 
2247 	if (session->ns_mover.md_sock < 0) {
2248 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
2249 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
2250 		return;
2251 	}
2252 
2253 	(void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE,
2254 	    &flag, sizeof (flag));
2255 	ndmp_set_socket_nodelay(session->ns_mover.md_sock);
2256 	ndmp_set_socket_rcv_buf(session->ns_mover.md_sock, 60 * KILOBYTE);
2257 	ndmp_set_socket_snd_buf(session->ns_mover.md_sock, 60 * KILOBYTE);
2258 
2259 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
2260 
2261 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
2262 		if (start_mover_for_backup(session) < 0) {
2263 			ndmpd_mover_error(session,
2264 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
2265 			return;
2266 		}
2267 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
2268 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2269 		    ntohs(from.sin_port));
2270 	} else {
2271 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
2272 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2273 		    ntohs(from.sin_port));
2274 	}
2275 
2276 	NDMP_LOG(LOG_DEBUG, "Received connection");
2277 
2278 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2279 }
2280 
2281 /*
2282  * tape_write
2283  *
2284  * Writes a data record to tape. Detects and handles EOT conditions.
2285  *
2286  * Parameters:
2287  *   session (input) - session pointer.
2288  *   data    (input) - data to be written.
2289  *   length  (input) - length of data to be written.
2290  *
2291  * Returns:
2292  *    0 - operation aborted by client.
2293  *   -1 - error.
2294  *   otherwise - number of bytes written.
2295  */
2296 static int
2297 tape_write(ndmpd_session_t *session, char *data, ssize_t length)
2298 {
2299 	ssize_t n;
2300 	int err;
2301 
2302 	for (; ; ) {
2303 		/*
2304 		 * Refer to the comment at the top of ndmpd_tape.c file for
2305 		 * Mammoth2 tape drives.
2306 		 */
2307 		if (session->ns_tape.td_eom_seen) {
2308 			NDMP_LOG(LOG_DEBUG, "eom_seen");
2309 			session->ns_tape.td_eom_seen = FALSE;
2310 			/*
2311 			 * End of media reached.
2312 			 * Notify client and wait for the client to
2313 			 * either abort the operation or continue the
2314 			 * operation after changing the tape.
2315 			 */
2316 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2317 			    ++ndmp_log_msg_id,
2318 			    "End of tape reached. Load next tape.\n");
2319 
2320 			err = change_tape(session);
2321 
2322 			/* Operation aborted or connection terminated? */
2323 			if (err < 0)
2324 				return (-1);
2325 
2326 			continue;
2327 		}
2328 
2329 		n = write(session->ns_tape.td_fd, data, length);
2330 		if (n < 0) {
2331 			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
2332 			return (-1);
2333 		}
2334 		NS_ADD(wtape, n);
2335 
2336 		if (n == 0 || n != length) {
2337 			if (n != 0) {
2338 				NDMP_LOG(LOG_DEBUG, "LEOT n: %d", n);
2339 
2340 				NDMP_LOG(LOG_DEBUG, "Backup one record");
2341 				(void) ndmp_mtioctl(session->ns_tape.td_fd,
2342 				    MTBSR, 1);
2343 
2344 				/* setting logical EOM */
2345 				ndmpd_write_eom(session->ns_tape.td_fd);
2346 			}
2347 
2348 			/*
2349 			 * End of media reached.
2350 			 * Notify client and wait for the client to
2351 			 * either abort the operation or continue the
2352 			 * operation after changing the tape.
2353 			 */
2354 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2355 			    ++ndmp_log_msg_id,
2356 			    "End of tape reached. Load next tape.\n");
2357 
2358 			err = change_tape(session);
2359 
2360 			/* Operation aborted or connection terminated? */
2361 			if (err < 0)
2362 				return (-1);
2363 
2364 			/* Retry the write to the new tape. */
2365 			continue;
2366 		}
2367 
2368 		session->ns_tape.td_record_count++;
2369 		return (n);
2370 	}
2371 }
2372 
2373 
2374 /*
2375  * tape_read
2376  *
2377  * Reads a data record from tape. Detects and handles EOT conditions.
2378  *
2379  * Parameters:
2380  *   session (input) - session pointer.
2381  *   data    (input) - location to read data to.
2382  *
2383  * Returns:
2384  *    0 - operation aborted.
2385  *   -1 - tape read error.
2386  *   otherwise - number of bytes read.
2387  */
2388 static int
2389 tape_read(ndmpd_session_t *session, char *data)
2390 {
2391 	ssize_t n;
2392 	int err;
2393 	int count = session->ns_mover.md_record_size;
2394 
2395 	for (; ; ) {
2396 		n = read(session->ns_tape.td_fd, data, count);
2397 		if (n < 0) {
2398 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
2399 			return (TAPE_READ_ERR);
2400 		}
2401 		NS_ADD(rtape, n);
2402 
2403 		if (n == 0) {
2404 			if (!is_writer_running(session))
2405 				return (TAPE_NO_WRITER_ERR);
2406 
2407 			/*
2408 			 * End of media reached.
2409 			 * Notify client and wait for the client to
2410 			 * either abort the data operation or continue the
2411 			 * operation after changing the tape.
2412 			 */
2413 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2414 			    ++ndmp_log_msg_id,
2415 			    "End of tape reached. Load next tape");
2416 
2417 			NDMP_LOG(LOG_DEBUG,
2418 			    "End of tape reached. Load next tape");
2419 
2420 			err = change_tape(session);
2421 
2422 			/* Operation aborted or connection terminated? */
2423 			if (err < 0) {
2424 				/*
2425 				 * K.L. Go back one record if it is read
2426 				 * but not used.
2427 				 */
2428 
2429 				if (count != session->ns_mover.md_record_size) {
2430 					(void) ndmp_mtioctl(
2431 					    session->ns_tape.td_fd, MTBSR, 1);
2432 				}
2433 				return (0);
2434 			}
2435 			/* Retry the read from the new tape. */
2436 			continue;
2437 		}
2438 
2439 		/* Change to pass Veritas Netbackup prequal test. */
2440 		data += n;
2441 		count -= n;
2442 		if (count <= 0) {
2443 			session->ns_mover.md_record_num++;
2444 			session->ns_tape.td_record_count++;
2445 			return (n);
2446 		}
2447 	}
2448 }
2449 
2450 /*
2451  * change_tape
2452  *
2453  * Send a notify_pause request (protocol version 1) or
2454  * notify_mover_pause request (protocol version 2) to the
2455  * NDMP client to inform
2456  * the client that a tape volume change is required.
2457  * Process messages until the data/mover operation is either aborted
2458  * or continued.
2459  *
2460  * Parameters:
2461  *   client_data (input) - session pointer.
2462  *
2463  * Returns:
2464  *   0 - operation has been continued.
2465  *  -1 - operation has been aborted.
2466  */
2467 static int
2468 change_tape(ndmpd_session_t *session)
2469 {
2470 	ndmp_notify_mover_paused_request request;
2471 
2472 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2473 
2474 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
2475 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
2476 	else
2477 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
2478 
2479 	request.reason = session->ns_mover.md_pause_reason;
2480 	request.seek_position = long_long_to_quad(0LL);
2481 
2482 	NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
2483 	    session->ns_mover.md_pause_reason);
2484 
2485 	if (ndmp_send_request(session->ns_connection,
2486 	    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2487 	    (void *) &request, 0) < 0) {
2488 		NDMP_LOG(LOG_DEBUG,
2489 		    "Sending notify_mover_paused request");
2490 		return (-1);
2491 	}
2492 	/*
2493 	 * Wait for until the state is changed by
2494 	 * an abort or continue request.
2495 	 */
2496 	nlp_ref_nw(session);
2497 	for (; ; ) {
2498 		NDMP_LOG(LOG_DEBUG, "calling nlp_wait_nw()");
2499 
2500 		nlp_wait_nw(session);
2501 
2502 		if (nlp_event_rv_get(session) < 0) {
2503 			nlp_unref_nw(session);
2504 			return (-1);
2505 		}
2506 
2507 		if (session->ns_eof == TRUE) {
2508 			NDMP_LOG(LOG_DEBUG, "session->ns_eof == TRUE");
2509 			nlp_unref_nw(session);
2510 			return (-1);
2511 		}
2512 
2513 		switch (session->ns_mover.md_state) {
2514 		case NDMP_MOVER_STATE_ACTIVE:
2515 			NDMP_LOG(LOG_DEBUG,
2516 			    "mover.state: NDMP_MOVER_STATE_ACTIVE");
2517 
2518 			nlp_unref_nw(session);
2519 			session->ns_tape.td_record_count = 0;
2520 			return (0);
2521 
2522 		case NDMP_MOVER_STATE_PAUSED:
2523 			NDMP_LOG(LOG_DEBUG,
2524 			    "mover.state: NDMP_MOVER_STATE_PAUSED");
2525 			continue;
2526 
2527 		default:
2528 			NDMP_LOG(LOG_DEBUG, "default");
2529 			nlp_unref_nw(session);
2530 			return (-1);
2531 		}
2532 	}
2533 
2534 	/* nlp_unref_nw(session); - statement never reached */
2535 }
2536 
2537 
2538 /*
2539  * discard_data
2540  *
2541  * Read and discard data from the data connection.
2542  * Called when a module has called ndmpd_seek() prior to
2543  * reading all of the data from the previous seek.
2544  *
2545  * Parameters:
2546  *   session (input) - session pointer.
2547  *
2548  * Returns:
2549  *   number of bytes read and discarded.
2550  *  -1 - error.
2551  */
2552 static int
2553 discard_data(ndmpd_session_t *session, ulong_t length)
2554 {
2555 	int n;
2556 	char *addr;
2557 
2558 	if ((addr = ndmp_malloc(length)) == NULL)
2559 		return (-1);
2560 
2561 	/* Read and discard the data. */
2562 	n = read(session->ns_mover.md_sock, addr, length);
2563 	if (n < 0) {
2564 		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
2565 		free(addr);
2566 		return (-1);
2567 	}
2568 
2569 	free(addr);
2570 	return (n);
2571 }
2572 
2573 
2574 /*
2575  * mover_tape_read_one_buf
2576  *
2577  * Read one buffer from the tape. This is used by mover_tape_reader
2578  *
2579  * Parameters:
2580  *   session (input) - session pointer.
2581  *   buf (input) - buffer read
2582  *
2583  * Returns:
2584  *   0: on success
2585  *  -1: otherwise
2586  */
2587 static int
2588 mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2589 {
2590 	int n;
2591 
2592 	tlm_buffer_mark_empty(buf);
2593 
2594 	/*
2595 	 * If the end of the mover window has been reached,
2596 	 * then notify the client that a seek is needed.
2597 	 * Remove the file handler to prevent this function from
2598 	 * being called. The handler will be reinstalled in
2599 	 * ndmpd_mover_continue.
2600 	 */
2601 
2602 	if (session->ns_mover.md_position >=
2603 	    session->ns_mover.md_window_offset +
2604 	    session->ns_mover.md_window_length) {
2605 		ndmp_notify_mover_paused_request pause_request;
2606 
2607 		NDMP_LOG(LOG_DEBUG, "end of mover window");
2608 
2609 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2610 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2611 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2612 		pause_request.seek_position =
2613 		    long_long_to_quad(session->ns_mover.md_position);
2614 
2615 		if (ndmp_send_request(session->ns_connection,
2616 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2617 		    (void *) &pause_request, 0) < 0) {
2618 			NDMP_LOG(LOG_DEBUG,
2619 			    "Sending notify_mover_paused request");
2620 			ndmpd_mover_error(session,
2621 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
2622 		}
2623 		buf->tb_errno = EIO;
2624 		return (TAPE_READ_ERR);
2625 	}
2626 
2627 	n = tape_read(session, buf->tb_buffer_data);
2628 
2629 	NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
2630 
2631 	if (n <= 0) {
2632 		if (n < 0)
2633 			ndmpd_mover_error(session,
2634 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
2635 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
2636 		return (TAPE_READ_ERR);
2637 	}
2638 
2639 	buf->tb_full = TRUE;
2640 	buf->tb_buffer_size = session->ns_mover.md_record_size;
2641 
2642 	/*
2643 	 * Discard data if the current data stream position is
2644 	 * prior to the seek position. This is necessary if a seek
2645 	 * request set the seek pointer to a position that is not a
2646 	 * record boundary. The seek request handler can only position
2647 	 * to the start of a record.
2648 	 */
2649 	if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
2650 		session->ns_mover.md_position =
2651 		    session->ns_mover.md_seek_position;
2652 
2653 	return (0);
2654 }
2655 
2656 
2657 /*
2658  * mover_tape_reader
2659  *
2660  * Mover tape reader thread. It is launched when the mover is started
2661  * for restore.
2662  *
2663  * Parameters:
2664  *   session (input) - session pointer.
2665  *
2666  * Returns:
2667  *   0: on success
2668  *  -1: otherwise
2669  */
2670 int
2671 mover_tape_reader(ndmpd_session_t *session)
2672 {
2673 	int bidx;	/* buffer index */
2674 	int rv;
2675 	ndmp_lbr_params_t *nlp;
2676 	tlm_buffer_t *buf;
2677 	tlm_buffers_t *bufs;
2678 	tlm_cmd_t *lcmd;	/* Local command */
2679 	tlm_commands_t *cmds;	/* Commands structure */
2680 
2681 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2682 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2683 		return (-1);
2684 	}
2685 
2686 	cmds = &nlp->nlp_cmds;
2687 	lcmd = cmds->tcs_command;
2688 	bufs = lcmd->tc_buffers;
2689 
2690 	lcmd->tc_ref++;
2691 	cmds->tcs_reader_count++;
2692 
2693 	/*
2694 	 * Let our parent thread know that we are running.
2695 	 */
2696 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
2697 
2698 	buf = tlm_buffer_in_buf(bufs, &bidx);
2699 	while (cmds->tcs_reader == TLM_RESTORE_RUN &&
2700 	    lcmd->tc_reader == TLM_RESTORE_RUN) {
2701 		buf = tlm_buffer_in_buf(bufs, NULL);
2702 
2703 		if (buf->tb_full) {
2704 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2705 			/*
2706 			 * The buffer is still full, wait for the consumer
2707 			 * thread to use it.
2708 			 */
2709 			tlm_buffer_out_buf_timed_wait(bufs, 100);
2710 
2711 		} else {
2712 			NDMP_LOG(LOG_DEBUG, "r%d", bidx);
2713 
2714 			rv = mover_tape_read_one_buf(session, buf);
2715 			/*
2716 			 * If there was an error while reading, such as
2717 			 * end of stream.
2718 			 */
2719 			if (rv < 0) {
2720 				NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
2721 				break;
2722 			}
2723 
2724 			/*
2725 			 * Can we do more buffering?
2726 			 */
2727 			if (is_buffer_erroneous(buf)) {
2728 				NDMP_LOG(LOG_DEBUG,
2729 				    "Exiting, errno: %d, eot: %d, eof: %d",
2730 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
2731 				break;
2732 			}
2733 
2734 			(void) tlm_buffer_advance_in_idx(bufs);
2735 			tlm_buffer_release_in_buf(bufs);
2736 			bidx = bufs->tbs_buffer_in;
2737 		}
2738 	}
2739 
2740 	/* If the consumer is waiting for us, wake it up. */
2741 	tlm_buffer_release_in_buf(bufs);
2742 
2743 	/*
2744 	 * Clean up.
2745 	 */
2746 	cmds->tcs_reader_count--;
2747 	lcmd->tc_ref--;
2748 	lcmd->tc_writer = TLM_STOP;
2749 	return (0);
2750 }
2751 
2752 
2753 /*
2754  * mover_socket_write_one_buf
2755  *
2756  * Write one buffer to the network socket. This is used by mover_socket_writer
2757  *
2758  * Parameters:
2759  *   session (input) - session pointer.
2760  *   buf (input) - buffer read
2761  *
2762  * Returns:
2763  *   0: on success
2764  *  -1: otherwise
2765  */
2766 static int
2767 mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2768 {
2769 	int n;
2770 
2771 	/* Write the data to the data connection. */
2772 	errno = 0;
2773 	n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
2774 	    buf->tb_buffer_size);
2775 
2776 	NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
2777 
2778 	if (n < 0) {
2779 		NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2780 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
2781 		return (-1);
2782 	}
2783 
2784 	session->ns_mover.md_position += n;
2785 	session->ns_mover.md_bytes_left_to_read -= n;
2786 	tlm_buffer_mark_empty(buf);
2787 
2788 	/*
2789 	 * If the read limit has been reached,
2790 	 * then remove the file handler to prevent this
2791 	 * function from getting called. The next mover_read request
2792 	 * will reinstall the handler.
2793 	 */
2794 	if (session->ns_mover.md_bytes_left_to_read == 0) {
2795 		NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
2796 		(void) ndmpd_remove_file_handler(session,
2797 		    session->ns_mover.md_sock);
2798 		return (-1);
2799 	}
2800 
2801 	return (0);
2802 }
2803 
2804 
2805 
2806 /*
2807  * mover_socket_writer
2808  *
2809  * Mover's socket writer thread. This thread sends the read buffer
2810  * from the tape to the data server through the network socket.
2811  *
2812  * Parameters:
2813  *   session (input) - session pointer.
2814  *
2815  * Returns:
2816  *   0: on success
2817  *  -1: otherwise
2818  */
2819 int
2820 mover_socket_writer(ndmpd_session_t *session)
2821 {
2822 	int bidx;	/* buffer index */
2823 	ndmp_lbr_params_t *nlp;
2824 	tlm_buffer_t *buf;
2825 	tlm_buffers_t *bufs;
2826 	tlm_cmd_t *lcmd;	/* Local command */
2827 	tlm_commands_t *cmds;	/* Commands structure */
2828 
2829 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2830 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2831 		return (-1);
2832 	}
2833 
2834 	cmds = &nlp->nlp_cmds;
2835 	lcmd = cmds->tcs_command;
2836 	bufs = lcmd->tc_buffers;
2837 
2838 	lcmd->tc_ref++;
2839 	cmds->tcs_writer_count++;
2840 
2841 	/*
2842 	 * Let our parent thread know that we are running.
2843 	 */
2844 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
2845 
2846 	bidx = bufs->tbs_buffer_out;
2847 	while (cmds->tcs_writer != (int)TLM_ABORT &&
2848 	    lcmd->tc_writer != (int)TLM_ABORT) {
2849 		buf = &bufs->tbs_buffer[bidx];
2850 
2851 		if (buf->tb_full) {
2852 			NDMP_LOG(LOG_DEBUG, "w%d", bidx);
2853 
2854 			if (mover_socket_write_one_buf(session, buf) < 0) {
2855 				NDMP_LOG(LOG_DEBUG,
2856 				    "mover_socket_write_one_buf() < 0");
2857 				break;
2858 			}
2859 
2860 			(void) tlm_buffer_advance_out_idx(bufs);
2861 			tlm_buffer_release_out_buf(bufs);
2862 			bidx = bufs->tbs_buffer_out;
2863 		} else {
2864 			if (lcmd->tc_writer != TLM_RESTORE_RUN) {
2865 				/* No more data is coming, time to exit */
2866 				NDMP_LOG(LOG_DEBUG, "Time to exit");
2867 				break;
2868 			}
2869 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
2870 			/*
2871 			 * The buffer is not full, wait for the producer
2872 			 * thread to fill it.
2873 			 */
2874 			tlm_buffer_in_buf_timed_wait(bufs, 100);
2875 		}
2876 	}
2877 
2878 	if (cmds->tcs_writer == (int)TLM_ABORT)
2879 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
2880 	if (lcmd->tc_writer == (int)TLM_ABORT)
2881 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
2882 
2883 	/* If the producer is waiting for us, wake it up. */
2884 	tlm_buffer_release_out_buf(bufs);
2885 
2886 	/*
2887 	 * Clean up.
2888 	 */
2889 	cmds->tcs_writer_count--;
2890 	lcmd->tc_ref--;
2891 	lcmd->tc_reader = TLM_STOP;
2892 	return (0);
2893 }
2894 
2895 
2896 /*
2897  * start_mover_for_restore
2898  *
2899  * Creates the mover tape reader and network writer threads for
2900  * the mover to perform the 3-way restore.
2901  *
2902  * Parameters:
2903  *   session (input) - session pointer.
2904  *
2905  * Returns:
2906  *   0: on success
2907  *  -1: otherwise
2908  */
2909 static int
2910 start_mover_for_restore(ndmpd_session_t *session)
2911 {
2912 	ndmp_lbr_params_t *nlp;
2913 	tlm_commands_t *cmds;
2914 	long xfer_size;
2915 	int rc;
2916 
2917 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2918 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2919 		return (-1);
2920 	}
2921 
2922 	cmds = &nlp->nlp_cmds;
2923 	(void) memset(cmds, 0, sizeof (*cmds));
2924 	cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
2925 	xfer_size = ndmp_buffer_get_size(session);
2926 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2927 	if (cmds->tcs_command == NULL)
2928 		return (-1);
2929 
2930 	cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
2931 	cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
2932 
2933 	/*
2934 	 * We intentionnally don't wait for the threads to start since the
2935 	 * reply of the request (which resulted in calling this function)
2936 	 * must be sent to the client before probable errors are sent
2937 	 * to the client.
2938 	 */
2939 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session);
2940 	if (rc == 0) {
2941 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
2942 	} else {
2943 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
2944 		    strerror(rc));
2945 		return (-1);
2946 	}
2947 
2948 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session);
2949 	if (rc == 0) {
2950 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
2951 	} else {
2952 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
2953 		    strerror(rc));
2954 		return (-1);
2955 	}
2956 
2957 	tlm_release_reader_writer_ipc(cmds->tcs_command);
2958 	return (0);
2959 }
2960 
2961 
2962 /*
2963  * mover_socket_read_one_buf
2964  *
2965  * Read one buffer from the network socket for the mover. This is used
2966  * by mover_socket_reader
2967  *
2968  * Parameters:
2969  *   session (input) - session pointer.
2970  *   buf (input) - buffer read
2971  *   read_size (input) - size to be read
2972  *
2973  * Returns:
2974  *   0: on success
2975  *  -1: otherwise
2976  */
2977 static int
2978 mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
2979     long read_size)
2980 {
2981 	int n, index;
2982 	long toread;
2983 
2984 	tlm_buffer_mark_empty(buf);
2985 	for (index = 0, toread = read_size; toread > 0; ) {
2986 		errno = 0;
2987 		NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
2988 
2989 		n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
2990 		    toread);
2991 		if (n == 0) {
2992 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
2993 			break;
2994 		} else if (n > 0) {
2995 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
2996 			index += n;
2997 			toread -= n;
2998 		} else {
2999 			buf->tb_eof = TRUE;
3000 			buf->tb_errno = errno;
3001 			buf->tb_buffer_size = 0;
3002 			NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
3003 			return (-1);
3004 		}
3005 	}
3006 
3007 	if (index > 0) {
3008 		buf->tb_full = TRUE;
3009 		buf->tb_buffer_size = read_size;
3010 		if (read_size > 0)
3011 			(void) memset(&buf->tb_buffer_data[index], 0,
3012 			    read_size - index);
3013 	} else {
3014 		buf->tb_eof = TRUE;
3015 		buf->tb_buffer_size = 0;
3016 	}
3017 
3018 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
3019 	    " errno: %d, size: %d, data: 0x%x",
3020 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
3021 	    buf->tb_buffer_size, buf->tb_buffer_data);
3022 
3023 	return (0);
3024 }
3025 
3026 
3027 
3028 /*
3029  * mover_socket_reader
3030  *
3031  * Mover socket reader thread. This is used when reading data from the
3032  * network socket for performing remote backups.
3033  *
3034  * Parameters:
3035  *   session (input) - session pointer.
3036  *
3037  * Returns:
3038  *   0: on success
3039  *  -1: otherwise
3040  */
3041 int
3042 mover_socket_reader(ndmpd_session_t *session)
3043 {
3044 	int bidx;	/* buffer index */
3045 	ndmp_lbr_params_t *nlp;
3046 	tlm_buffer_t *buf;
3047 	tlm_buffers_t *bufs;
3048 	tlm_cmd_t *lcmd;	/* Local command */
3049 	tlm_commands_t *cmds;	/* Commands structure */
3050 	static int nr = 0;
3051 
3052 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3053 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3054 		return (-1);
3055 	}
3056 
3057 	cmds = &nlp->nlp_cmds;
3058 	lcmd = cmds->tcs_command;
3059 	bufs = lcmd->tc_buffers;
3060 
3061 	lcmd->tc_ref++;
3062 	cmds->tcs_reader_count++;
3063 
3064 	/*
3065 	 * Let our parent thread know that we are running.
3066 	 */
3067 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
3068 
3069 	bidx = bufs->tbs_buffer_in;
3070 	while (cmds->tcs_reader == TLM_BACKUP_RUN &&
3071 	    lcmd->tc_reader == TLM_BACKUP_RUN) {
3072 		buf = &bufs->tbs_buffer[bidx];
3073 
3074 		if (buf->tb_full) {
3075 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
3076 			/*
3077 			 * The buffer is still full, wait for the consumer
3078 			 * thread to use it.
3079 			 */
3080 			tlm_buffer_out_buf_timed_wait(bufs, 100);
3081 		} else {
3082 			NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
3083 
3084 			(void) mover_socket_read_one_buf(session, buf,
3085 			    bufs->tbs_data_transfer_size);
3086 
3087 			/*
3088 			 * Can we do more buffering?
3089 			 */
3090 			if (is_buffer_erroneous(buf)) {
3091 				NDMP_LOG(LOG_DEBUG,
3092 				    "Exiting, errno: %d, eot: %d, eof: %d",
3093 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
3094 				break;
3095 			}
3096 
3097 			(void) tlm_buffer_advance_in_idx(bufs);
3098 			tlm_buffer_release_in_buf(bufs);
3099 			bidx = bufs->tbs_buffer_in;
3100 		}
3101 	}
3102 
3103 	if (cmds->tcs_reader != TLM_BACKUP_RUN)
3104 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
3105 	if (lcmd->tc_reader != TLM_BACKUP_RUN)
3106 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
3107 	NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
3108 
3109 	/* If the consumer is waiting for us, wake it up. */
3110 	tlm_buffer_release_in_buf(bufs);
3111 
3112 	/*
3113 	 * Clean up.
3114 	 */
3115 	cmds->tcs_reader_count--;
3116 	lcmd->tc_ref--;
3117 	lcmd->tc_writer = TLM_STOP;
3118 	return (0);
3119 }
3120 
3121 
3122 /*
3123  * mover_tape_writer_one_buf
3124  *
3125  * Write one buffer for the mover to the local tape device. This is
3126  * used by mover_tape_writer thread.
3127  *
3128  * Parameters:
3129  *   session (input) - session pointer.
3130  *   buf (input) - buffer read
3131  *
3132  * Returns:
3133  *   0: on success
3134  *  -1: otherwise
3135  */
3136 static int
3137 mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
3138 {
3139 	int n;
3140 
3141 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
3142 	    " errno: %d, size: %d, data: 0x%x",
3143 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
3144 	    buf->tb_buffer_size, buf->tb_buffer_data);
3145 
3146 	n = tape_write(session, buf->tb_buffer_data, buf->tb_buffer_size);
3147 
3148 	NDMP_LOG(LOG_DEBUG, "n: %d", n);
3149 
3150 	if (n <= 0) {
3151 		ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
3152 		    : NDMP_MOVER_HALT_INTERNAL_ERROR));
3153 		return (-1);
3154 	}
3155 	session->ns_mover.md_position += n;
3156 	session->ns_mover.md_data_written += n;
3157 	session->ns_mover.md_record_num++;
3158 
3159 	NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
3160 	tlm_buffer_mark_empty(buf);
3161 
3162 	return (0);
3163 }
3164 
3165 
3166 /*
3167  * mover_tape_writer
3168  *
3169  * Mover tape writer thread. This is used for performing remote backups
3170  * in a 3-way configuration. It writes the data from network socket to
3171  * the locally attached tape device.
3172  *
3173  * Parameters:
3174  *   session (input) - session pointer.
3175  *
3176  * Returns:
3177  *   0: on success
3178  *  -1: otherwise
3179  */
3180 int
3181 mover_tape_writer(ndmpd_session_t *session)
3182 {
3183 	int bidx;
3184 	ndmp_lbr_params_t *nlp;
3185 	tlm_buffer_t *buf;
3186 	tlm_buffers_t *bufs;
3187 	tlm_cmd_t *lcmd;
3188 	tlm_commands_t *cmds;
3189 	static int nw = 0;
3190 
3191 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3192 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3193 		return (-1);
3194 	}
3195 
3196 	cmds = &nlp->nlp_cmds;
3197 	lcmd = cmds->tcs_command;
3198 	bufs = lcmd->tc_buffers;
3199 
3200 	lcmd->tc_ref++;
3201 	cmds->tcs_writer_count++;
3202 
3203 	/*
3204 	 * Let our parent thread know that we are running.
3205 	 */
3206 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
3207 
3208 	bidx = bufs->tbs_buffer_out;
3209 	buf = &bufs->tbs_buffer[bidx];
3210 	while (cmds->tcs_writer != (int)TLM_ABORT &&
3211 	    lcmd->tc_writer != (int)TLM_ABORT) {
3212 		if (buf->tb_full) {
3213 			NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
3214 
3215 			if (mover_tape_write_one_buf(session, buf) < 0) {
3216 				NDMP_LOG(LOG_DEBUG,
3217 				    "mover_tape_write_one_buf() failed");
3218 				break;
3219 			}
3220 
3221 			(void) tlm_buffer_advance_out_idx(bufs);
3222 			tlm_buffer_release_out_buf(bufs);
3223 			bidx = bufs->tbs_buffer_out;
3224 			buf = &bufs->tbs_buffer[bidx];
3225 		} else {
3226 			if (lcmd->tc_writer != TLM_BACKUP_RUN) {
3227 				/* No more data is coming, time to exit */
3228 				NDMP_LOG(LOG_DEBUG, "Time to exit");
3229 				break;
3230 			}
3231 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
3232 			/*
3233 			 * The buffer is not full, wait for the producer
3234 			 * thread to fill it.
3235 			 */
3236 			tlm_buffer_in_buf_timed_wait(bufs, 100);
3237 		}
3238 	}
3239 
3240 	if (cmds->tcs_writer == (int)TLM_ABORT)
3241 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
3242 	if (lcmd->tc_writer == (int)TLM_ABORT)
3243 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
3244 	NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
3245 
3246 	if (buf->tb_errno == 0) {
3247 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3248 	} else {
3249 		NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
3250 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
3251 	}
3252 
3253 	/* If the producer is waiting for us, wake it up. */
3254 	tlm_buffer_release_out_buf(bufs);
3255 
3256 	/*
3257 	 * Clean up.
3258 	 */
3259 	cmds->tcs_writer_count--;
3260 	lcmd->tc_ref--;
3261 	lcmd->tc_reader = TLM_STOP;
3262 	return (0);
3263 }
3264 
3265 
3266 /*
3267  * start_mover_for_backup
3268  *
3269  * Starts a remote backup by running socket reader and tape
3270  * writer threads. The mover runs a remote backup in a 3-way backup
3271  * configuration.
3272  *
3273  * Parameters:
3274  *   session (input) - session pointer.
3275  *
3276  * Returns:
3277  *   0: on success
3278  *  -1: otherwise
3279  */
3280 static int
3281 start_mover_for_backup(ndmpd_session_t *session)
3282 {
3283 	ndmp_lbr_params_t *nlp;
3284 	tlm_commands_t *cmds;
3285 	int rc;
3286 
3287 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3288 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3289 		return (-1);
3290 	}
3291 
3292 	cmds = &nlp->nlp_cmds;
3293 	(void) memset(cmds, 0, sizeof (*cmds));
3294 	cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
3295 	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
3296 	    session->ns_mover.md_record_size);
3297 	if (cmds->tcs_command == NULL)
3298 		return (-1);
3299 
3300 	cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
3301 	cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
3302 
3303 	/*
3304 	 * We intentionally don't wait for the threads to start since the
3305 	 * reply of the request (which resulted in calling this function)
3306 	 * must be sent to the client before probable errors are sent
3307 	 * to the client.
3308 	 */
3309 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session);
3310 	if (rc == 0) {
3311 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
3312 	} else {
3313 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
3314 		    strerror(rc));
3315 		return (-1);
3316 	}
3317 
3318 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session);
3319 	if (rc == 0) {
3320 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
3321 	} else {
3322 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
3323 		    strerror(rc));
3324 		return (-1);
3325 	}
3326 
3327 	tlm_release_reader_writer_ipc(cmds->tcs_command);
3328 	return (0);
3329 }
3330 
3331 
3332 /*
3333  * is_writer_running
3334  *
3335  * Find out if the writer thread has started or not.
3336  *
3337  * Parameters:
3338  *   session (input) - session pointer.
3339  *
3340  * Returns:
3341  *   0: not started
3342  *   non-zero: started
3343  *	Note: non-zero is also returned if the backup type is
3344  *		neither TAR nor DUMP.  I.e. the is_writer_running()
3345  *		check does not apply in this case and things should
3346  * 		appear successful.
3347  */
3348 static boolean_t
3349 is_writer_running(ndmpd_session_t *session)
3350 {
3351 	boolean_t rv;
3352 	ndmp_lbr_params_t *nlp;
3353 
3354 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3355 		return (1);
3356 
3357 	if (session == NULL)
3358 		rv = 0;
3359 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
3360 		rv = 0;
3361 	else
3362 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3363 
3364 	return (rv);
3365 }
3366 
3367 
3368 /*
3369  * is_writer_running_v3
3370  *
3371  * Find out if the writer thread has started or not.
3372  *
3373  * Parameters:
3374  *   session (input) - session pointer.
3375  *
3376  * Returns:
3377  *   0: not started
3378  *   non-zero: started
3379  *	Note: non-zero is also returned if the backup type is
3380  *		neither TAR nor DUMP.  I.e. the is_writer_running()
3381  *		check does not apply in this case and things should
3382  * 		appear successful.
3383  */
3384 static boolean_t
3385 is_writer_running_v3(ndmpd_session_t *session)
3386 {
3387 	boolean_t rv;
3388 	ndmp_lbr_params_t *nlp;
3389 
3390 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3391 		return (1);
3392 
3393 	if (session == NULL)
3394 		rv = 0;
3395 	else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
3396 		rv = 1;
3397 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
3398 		rv = 0;
3399 	else
3400 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3401 
3402 	return (rv);
3403 }
3404 
3405 
3406 /*
3407  * ndmpd_mover_wait_v3
3408  *
3409  * Take the mover state to PAUSED state
3410  *
3411  * Parameters:
3412  *   session (input) - session pointer.
3413  *
3414  * Returns:
3415  *   0: on success
3416  *  -1: otherwise
3417  */
3418 int
3419 ndmpd_mover_wait_v3(ndmpd_session_t *session)
3420 {
3421 	int rv = 0;
3422 
3423 	nlp_ref_nw(session);
3424 	for (; ; ) {
3425 		nlp_wait_nw(session);
3426 
3427 		if (nlp_event_rv_get(session) < 0) {
3428 			rv = -1;
3429 			break;
3430 		}
3431 		if (session->ns_eof) {
3432 			NDMP_LOG(LOG_DEBUG, "session->ns_eof");
3433 			rv = -1;
3434 			break;
3435 		}
3436 		if (session->ns_data.dd_abort) {
3437 			NDMP_LOG(LOG_DEBUG, "data.abort");
3438 			rv = -1;
3439 			break;
3440 		}
3441 		if (session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
3442 			NDMP_LOG(LOG_DEBUG,
3443 			    "mover.state: NDMP_MOVER_STATE_ACTIVE");
3444 			session->ns_tape.td_record_count = 0;
3445 			rv = 0;
3446 			break;
3447 		} else if (session->ns_mover.md_state ==
3448 		    NDMP_MOVER_STATE_PAUSED) {
3449 			NDMP_LOG(LOG_DEBUG,
3450 			    "mover.state: NDMP_MOVER_STATE_PAUSED");
3451 		} else {
3452 			NDMP_LOG(LOG_DEBUG, "default");
3453 			rv = -1;
3454 			break;
3455 		}
3456 	}
3457 
3458 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
3459 	nlp_unref_nw(session);
3460 	return (rv);
3461 }
3462 
3463 /*
3464  * ndmpd_mover_error_send
3465  *
3466  * This function sends the notify message to the client.
3467  *
3468  * Parameters:
3469  *   session (input) - session pointer.
3470  *   reason  (input) - halt reason.
3471  *
3472  * Returns:
3473  *   Error code
3474  */
3475 int
3476 ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3477 {
3478 	ndmp_notify_mover_halted_request req;
3479 
3480 	req.reason = reason;
3481 	req.text_reason = "";
3482 
3483 	return (ndmp_send_request(session->ns_connection,
3484 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3485 }
3486 
3487 
3488 /*
3489  * ndmpd_mover_error_send_v4
3490  *
3491  * This function sends the notify message to the client.
3492  *
3493  * Parameters:
3494  *   session (input) - session pointer.
3495  *   reason  (input) - halt reason.
3496  *
3497  * Returns:
3498  *   Error code
3499  */
3500 int
3501 ndmpd_mover_error_send_v4(ndmpd_session_t *session,
3502     ndmp_mover_halt_reason reason)
3503 {
3504 	ndmp_notify_mover_halted_request_v4 req;
3505 
3506 	req.reason = reason;
3507 
3508 	return (ndmp_send_request(session->ns_connection,
3509 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3510 }
3511 
3512 
3513 /*
3514  * ndmpd_mover_error
3515  *
3516  * This function is called when an unrecoverable mover error
3517  * has been detected. A notify message is sent to the client and the
3518  * mover is placed into the halted state.
3519  *
3520  * Parameters:
3521  *   session (input) - session pointer.
3522  *   reason  (input) - halt reason.
3523  *
3524  * Returns:
3525  *   void.
3526  */
3527 void
3528 ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3529 {
3530 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
3531 	    (session->ns_protocol_version > NDMPV2 &&
3532 	    session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
3533 		return;
3534 
3535 	if (session->ns_protocol_version == NDMPV4) {
3536 		if (ndmpd_mover_error_send_v4(session, reason) < 0)
3537 			NDMP_LOG(LOG_DEBUG,
3538 			    "Error sending notify_mover_halted request");
3539 	} else {
3540 		/* No media error in V3 */
3541 		if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
3542 			reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
3543 		if (ndmpd_mover_error_send(session, reason) < 0)
3544 			NDMP_LOG(LOG_DEBUG,
3545 			    "Error sending notify_mover_halted request");
3546 	}
3547 
3548 	if (session->ns_mover.md_listen_sock != -1) {
3549 		(void) ndmpd_remove_file_handler(session,
3550 		    session->ns_mover.md_listen_sock);
3551 		(void) close(session->ns_mover.md_listen_sock);
3552 		session->ns_mover.md_listen_sock = -1;
3553 	}
3554 	if (session->ns_mover.md_sock != -1) {
3555 		(void) ndmpd_remove_file_handler(session,
3556 		    session->ns_mover.md_sock);
3557 		(void) close(session->ns_mover.md_sock);
3558 		session->ns_mover.md_sock = -1;
3559 	}
3560 
3561 	session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
3562 	session->ns_mover.md_halt_reason = reason;
3563 }
3564 
3565 
3566 /*
3567  * mover_pause_v3
3568  *
3569  * Send an ndmp_notify_mover_paused request to the
3570  * NDMP client to inform the client that its attention is required.
3571  * Process messages until the data/mover operation is either aborted
3572  * or continued.
3573  *
3574  * Parameters:
3575  *   client_data (input) - session pointer.
3576  *   reason (input) - pause reason.
3577  *
3578  * Returns:
3579  *   0 - operation has been continued.
3580  *  -1 - operation has been aborted.
3581  */
3582 static int
3583 mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
3584 {
3585 	int rv;
3586 	ndmp_notify_mover_paused_request request;
3587 
3588 	rv = 0;
3589 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3590 	session->ns_mover.md_pause_reason = reason;
3591 	session->ns_mover.md_pre_cond = FALSE;
3592 
3593 	request.reason = session->ns_mover.md_pause_reason;
3594 	request.seek_position =
3595 	    long_long_to_quad(session->ns_mover.md_position);
3596 
3597 	if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
3598 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
3599 		NDMP_LOG(LOG_DEBUG,
3600 		    "Error sending notify_mover_paused_request");
3601 		return (-1);
3602 	}
3603 
3604 	/*
3605 	 * 3-way operations are single-thread.  The same thread
3606 	 * should process the messages.
3607 	 *
3608 	 * 2-way operations are multi-thread.  The main thread
3609 	 * processes the messages.  We just need to wait and
3610 	 * see if the mover state changes or the operation aborts.
3611 	 */
3612 	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
3613 		/*
3614 		 * Process messages until the state is changed by
3615 		 * an abort, continue, or close request .
3616 		 */
3617 		for (; ; ) {
3618 			if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
3619 				return (-1);
3620 
3621 			if (session->ns_eof == TRUE)
3622 				return (-1);
3623 
3624 			switch (session->ns_mover.md_state) {
3625 			case NDMP_MOVER_STATE_ACTIVE:
3626 				session->ns_tape.td_record_count = 0;
3627 				return (0);
3628 
3629 			case NDMP_MOVER_STATE_PAUSED:
3630 				continue;
3631 
3632 			default:
3633 				return (-1);
3634 			}
3635 		}
3636 
3637 	} else {
3638 		if (session->ns_mover.md_data_addr.addr_type ==
3639 		    NDMP_ADDR_LOCAL) {
3640 			rv = ndmpd_mover_wait_v3(session);
3641 		} else {
3642 			NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
3643 			    session->ns_mover.md_data_addr.addr_type);
3644 			rv = -1;
3645 		}
3646 	}
3647 
3648 	return (rv);
3649 }
3650 
3651 
3652 /*
3653  * mover_tape_write_v3
3654  *
3655  * Writes a data record to tape. Detects and handles EOT conditions.
3656  *
3657  * Parameters:
3658  *   session (input) - session pointer.
3659  *   data    (input) - data to be written.
3660  *   length  (input) - length of data to be written.
3661  *
3662  * Returns:
3663  *    0 - operation aborted by client.
3664  *   -1 - error.
3665  *   otherwise - number of bytes written.
3666  */
3667 static int
3668 mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
3669 {
3670 	ssize_t n;
3671 	int err;
3672 
3673 	for (; ; ) {
3674 		/*
3675 		 * Refer to the comment at the top of ndmpd_tape.c file for
3676 		 * Mammoth2 tape drives.
3677 		 */
3678 		if (session->ns_tape.td_eom_seen) {
3679 			NDMP_LOG(LOG_DEBUG, "eom_seen");
3680 
3681 			session->ns_tape.td_eom_seen = FALSE;
3682 			/*
3683 			 * End of media reached.
3684 			 * Notify client and wait for the client to
3685 			 * either abort the operation or continue the
3686 			 * operation after changing the tape.
3687 			 */
3688 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3689 			    ++ndmp_log_msg_id,
3690 			    "End of tape reached. Load next tape");
3691 
3692 			err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM);
3693 
3694 			/* Operation aborted or connection terminated? */
3695 			if (err < 0)
3696 				return (-1);
3697 
3698 			/* Retry the write to the new tape. */
3699 			continue;
3700 		}
3701 
3702 		/*
3703 		 * Enforce mover window on write.
3704 		 */
3705 		if (session->ns_mover.md_position >=
3706 		    session->ns_mover.md_window_offset +
3707 		    session->ns_mover.md_window_length) {
3708 			NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
3709 
3710 			err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW);
3711 			/* Operation aborted or connection terminated? */
3712 			if (err < 0)
3713 				return (-1);
3714 
3715 		}
3716 
3717 		n = write(session->ns_tape.td_fd, data, length);
3718 		if (n < 0) {
3719 			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3720 			return (-1);
3721 		}
3722 		NS_ADD(wtape, n);
3723 
3724 		if (n == 0 || n != length) {
3725 			if (n != 0) {
3726 				/*
3727 				 * Backup one record since the record
3728 				 * hits the EOM.
3729 				 */
3730 				NDMP_LOG(LOG_DEBUG, "Back up one record");
3731 				(void) ndmp_mtioctl(session->ns_tape.td_fd,
3732 				    MTBSR, 1);
3733 
3734 				/* setting logical EOM */
3735 				ndmpd_write_eom(session->ns_tape.td_fd);
3736 			}
3737 
3738 			/*
3739 			 * End of media reached.
3740 			 * Notify client and wait for the client to
3741 			 * either abort the operation or continue the
3742 			 * operation after changing the tape.
3743 			 */
3744 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3745 			    ++ndmp_log_msg_id,
3746 			    "End of tape reached. Load next tape");
3747 
3748 			err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM);
3749 
3750 			/* Operation aborted or connection terminated? */
3751 			if (err < 0)
3752 				return (-1);
3753 
3754 			/* Retry the write to the new tape. */
3755 			continue;
3756 		}
3757 
3758 		session->ns_tape.td_record_count++;
3759 		return (n);
3760 	}
3761 }
3762 
3763 
3764 /*
3765  * mover_tape_flush_v3
3766  *
3767  * Writes all remaining buffered data to tape. A partial record is
3768  * padded out to a full record with zeros.
3769  *
3770  * Parameters:
3771  *   session (input) - session pointer.
3772  *   data    (input) - data to be written.
3773  *   length  (input) - length of data to be written.
3774  *
3775  * Returns:
3776  *   -1 - error.
3777  *   otherwise - number of bytes written.
3778  */
3779 static int
3780 mover_tape_flush_v3(ndmpd_session_t *session)
3781 {
3782 	int n;
3783 
3784 	if (session->ns_mover.md_w_index == 0)
3785 		return (0);
3786 
3787 	(void) memset((void*)&session->ns_mover.md_buf[session->
3788 	    ns_mover.md_w_index], 0,
3789 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3790 
3791 	n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3792 	    session->ns_mover.md_record_size);
3793 	if (n < 0) {
3794 		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3795 		return (-1);
3796 	}
3797 
3798 	session->ns_mover.md_w_index = 0;
3799 	session->ns_mover.md_position += n;
3800 	return (n);
3801 }
3802 
3803 
3804 /*
3805  * ndmpd_local_write_v3
3806  *
3807  * Buffers and writes data to the tape device.
3808  * A full tape record is buffered before being written.
3809  *
3810  * Parameters:
3811  *   session    (input) - session pointer.
3812  *   data       (input) - data to be written.
3813  *   length     (input) - data length.
3814  *
3815  * Returns:
3816  *   0 - data successfully written.
3817  *  -1 - error.
3818  */
3819 int
3820 ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
3821 {
3822 	ulong_t count = 0;
3823 	ssize_t n;
3824 	ulong_t len;
3825 
3826 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
3827 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
3828 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
3829 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
3830 		return (-1);
3831 	}
3832 
3833 	/*
3834 	 * A length of 0 indicates that any buffered data should be
3835 	 * flushed to tape.
3836 	 */
3837 	if (length == 0) {
3838 		if (session->ns_mover.md_w_index == 0)
3839 			return (0);
3840 
3841 		(void) memset((void*)&session->ns_mover.md_buf[session->
3842 		    ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
3843 		    session->ns_mover.md_w_index);
3844 
3845 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3846 		    session->ns_mover.md_record_size);
3847 		if (n <= 0) {
3848 			ndmpd_mover_error(session,
3849 			    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3850 			    NDMP_MOVER_HALT_MEDIA_ERROR));
3851 			return (-1);
3852 		}
3853 
3854 		session->ns_mover.md_position += n;
3855 		session->ns_mover.md_data_written += n;
3856 		session->ns_mover.md_record_num++;
3857 		session->ns_mover.md_w_index = 0;
3858 		return (0);
3859 	}
3860 
3861 	/* Break the data into records. */
3862 	while (count < length) {
3863 		/*
3864 		 * Determine if data needs to be buffered or
3865 		 * can be written directly from user supplied location.
3866 		 * We can fast path the write if there is no pending
3867 		 * buffered data and there is at least a full records worth
3868 		 * of data to be written.
3869 		 */
3870 		if (session->ns_mover.md_w_index == 0 &&
3871 		    length - count >= session->ns_mover.md_record_size) {
3872 			n = mover_tape_write_v3(session, &data[count],
3873 			    session->ns_mover.md_record_size);
3874 			if (n <= 0) {
3875 				ndmpd_mover_error(session,
3876 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3877 				    NDMP_MOVER_HALT_MEDIA_ERROR));
3878 				return (-1);
3879 			}
3880 
3881 			session->ns_mover.md_position += n;
3882 			session->ns_mover.md_data_written += n;
3883 			session->ns_mover.md_record_num++;
3884 			count += n;
3885 			continue;
3886 		}
3887 
3888 		/* Buffer the data */
3889 		len = length - count;
3890 		if (len > session->ns_mover.md_record_size -
3891 		    session->ns_mover.md_w_index)
3892 			len = session->ns_mover.md_record_size -
3893 			    session->ns_mover.md_w_index;
3894 
3895 		(void) memcpy(&session->ns_mover.md_buf[session->
3896 		    ns_mover.md_w_index], &data[count], len);
3897 		session->ns_mover.md_w_index += len;
3898 		count += len;
3899 
3900 		/* Write the buffer if its full */
3901 		if (session->ns_mover.md_w_index ==
3902 		    session->ns_mover.md_record_size) {
3903 			n = mover_tape_write_v3(session,
3904 			    session->ns_mover.md_buf,
3905 			    session->ns_mover.md_record_size);
3906 			if (n < 0) {
3907 				ndmpd_mover_error(session,
3908 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3909 				    NDMP_MOVER_HALT_MEDIA_ERROR));
3910 				return (-1);
3911 			}
3912 
3913 			session->ns_mover.md_position += n;
3914 			session->ns_mover.md_data_written += n;
3915 			session->ns_mover.md_record_num++;
3916 			session->ns_mover.md_w_index = 0;
3917 		}
3918 	}
3919 
3920 	return (0);
3921 }
3922 
3923 
3924 /*
3925  * mover_data_read_v3
3926  *
3927  * Reads backup data from the data connection and writes the
3928  * received data to the tape device.
3929  *
3930  * Parameters:
3931  *   cookie  (input) - session pointer.
3932  *   fd      (input) - file descriptor.
3933  *   mode    (input) - select mode.
3934  *
3935  * Returns:
3936  *   void.
3937  */
3938 /*ARGSUSED*/
3939 static void
3940 mover_data_read_v3(void *cookie, int fd, ulong_t mode)
3941 {
3942 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3943 	int n;
3944 	ulong_t index;
3945 
3946 	n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
3947 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3948 
3949 	/*
3950 	 * Since this function is only called when select believes data
3951 	 * is available to be read, a return of zero indicates the
3952 	 * connection has been closed.
3953 	 */
3954 	if (n <= 0) {
3955 		if (n < 0 && errno == EWOULDBLOCK) {
3956 			NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
3957 			return;
3958 		}
3959 		NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
3960 
3961 		/* Save the index since mover_tape_flush_v3 resets it. */
3962 		index = session->ns_mover.md_w_index;
3963 
3964 		/* Flush any buffered data to tape. */
3965 		if (mover_tape_flush_v3(session) > 0) {
3966 			session->ns_mover.md_data_written += index;
3967 			session->ns_mover.md_record_num++;
3968 		}
3969 
3970 		if (n == 0)
3971 			ndmpd_mover_error(session,
3972 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
3973 		else
3974 			ndmpd_mover_error(session,
3975 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
3976 
3977 		return;
3978 	}
3979 
3980 	NDMP_LOG(LOG_DEBUG, "n %d", n);
3981 
3982 	session->ns_mover.md_w_index += n;
3983 
3984 	if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
3985 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3986 		    session->ns_mover.md_record_size);
3987 		if (n <= 0) {
3988 			ndmpd_mover_error(session,
3989 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3990 			    NDMP_MOVER_HALT_MEDIA_ERROR));
3991 			return;
3992 		}
3993 
3994 		session->ns_mover.md_position += n;
3995 		session->ns_mover.md_w_index = 0;
3996 		session->ns_mover.md_data_written += n;
3997 		session->ns_mover.md_record_num++;
3998 	}
3999 }
4000 
4001 /*
4002  * mover_tape_read_v3
4003  *
4004  * Reads a data record from tape. Detects and handles EOT conditions.
4005  *
4006  * Parameters:
4007  *   session (input) - session pointer.
4008  *   data    (input) - location to read data to.
4009  *
4010  * Returns:
4011  *   0 - operation aborted.
4012  *   TAPE_READ_ERR - tape read IO error.
4013  *   TAPE_NO_WRITER_ERR - no writer is running during tape read
4014  *   otherwise - number of bytes read.
4015  */
4016 static int
4017 mover_tape_read_v3(ndmpd_session_t *session, char *data)
4018 {
4019 	ssize_t	 n;
4020 	int err;
4021 	int count;
4022 
4023 	count = session->ns_mover.md_record_size;
4024 	for (; ; ) {
4025 		n = read(session->ns_tape.td_fd, data, count);
4026 		if (n < 0) {
4027 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
4028 			return (TAPE_READ_ERR);
4029 		}
4030 		NS_ADD(rtape, n);
4031 
4032 		if (n == 0) {
4033 			if (!is_writer_running_v3(session))
4034 				return (TAPE_NO_WRITER_ERR);
4035 
4036 			/*
4037 			 * End of media reached.
4038 			 * Notify client and wait for the client to
4039 			 * either abort the data operation or continue the
4040 			 * operation after changing the tape.
4041 			 */
4042 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
4043 			    ++ndmp_log_msg_id,
4044 			    "End of tape reached. Load next tape");
4045 
4046 			err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOF);
4047 
4048 			/* Operation aborted or connection terminated? */
4049 			if (err < 0) {
4050 				/*
4051 				 * Back up one record if it's read but not
4052 				 * used.
4053 				 */
4054 				if (count != session->ns_mover.md_record_size)
4055 					(void) ndmp_mtioctl(
4056 					    session->ns_tape.td_fd, MTBSR, 1);
4057 				return (0);
4058 			}
4059 
4060 			/* Retry the read from the new tape. */
4061 			continue;
4062 		}
4063 
4064 		data += n;
4065 		count -= n;
4066 		if (count <= 0) {
4067 			session->ns_mover.md_record_num++;
4068 			session->ns_tape.td_record_count++;
4069 			return (n);
4070 		}
4071 	}
4072 }
4073 
4074 
4075 /*
4076  * mover_data_write_v3
4077  *
4078  * Reads backup data from the tape device and writes the
4079  * data to the data connection.
4080  * This function is called by ndmpd_select when the data connection
4081  * is ready for more data to be written.
4082  *
4083  * Parameters:
4084  *   cookie  (input) - session pointer.
4085  *   fd      (input) - file descriptor.
4086  *   mode    (input) - select mode.
4087  *
4088  * Returns:
4089  *   void.
4090  */
4091 /*ARGSUSED*/
4092 static void
4093 mover_data_write_v3(void *cookie, int fd, ulong_t mode)
4094 {
4095 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
4096 	int n;
4097 	ulong_t len;
4098 	u_longlong_t wlen;
4099 	ndmp_notify_mover_paused_request pause_request;
4100 
4101 	/*
4102 	 * If the end of the mover window has been reached,
4103 	 * then notify the client that a seek is needed.
4104 	 * Remove the file handler to prevent this function from
4105 	 * being called. The handler will be reinstalled in
4106 	 * ndmpd_mover_continue.
4107 	 */
4108 	if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
4109 	    + session->ns_mover.md_window_length) {
4110 		NDMP_LOG(LOG_DEBUG,
4111 		    "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
4112 
4113 		session->ns_mover.md_w_index = 0;
4114 		session->ns_mover.md_r_index = 0;
4115 
4116 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
4117 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
4118 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
4119 		pause_request.seek_position =
4120 		    long_long_to_quad(session->ns_mover.md_position);
4121 		session->ns_mover.md_seek_position =
4122 		    session->ns_mover.md_position;
4123 
4124 		(void) ndmpd_remove_file_handler(session, fd);
4125 
4126 		if (ndmp_send_request(session->ns_connection,
4127 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
4128 		    (void *)&pause_request, 0) < 0) {
4129 			NDMP_LOG(LOG_DEBUG,
4130 			    "Sending notify_mover_paused request");
4131 			ndmpd_mover_error(session,
4132 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
4133 		}
4134 		return;
4135 	}
4136 
4137 	/*
4138 	 * Read more data into the tape buffer if the buffer is empty.
4139 	 */
4140 	if (session->ns_mover.md_w_index == 0) {
4141 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4142 
4143 		NDMP_LOG(LOG_DEBUG,
4144 		    "read %u bytes from tape", n);
4145 
4146 		if (n <= 0) {
4147 			ndmpd_mover_error(session, (n == 0 ?
4148 			    NDMP_MOVER_HALT_ABORTED
4149 			    : NDMP_MOVER_HALT_MEDIA_ERROR));
4150 			return;
4151 		}
4152 
4153 		/*
4154 		 * Discard data if the current data stream position is
4155 		 * prior to the seek position. This is necessary if a seek
4156 		 * request set the seek pointer to a position that is not a
4157 		 * record boundary. The seek request handler can only position
4158 		 * to the start of a record.
4159 		 */
4160 		if (session->ns_mover.md_position <
4161 		    session->ns_mover.md_seek_position) {
4162 			session->ns_mover.md_r_index =
4163 			    session->ns_mover.md_seek_position -
4164 			    session->ns_mover.md_position;
4165 			session->ns_mover.md_position =
4166 			    session->ns_mover.md_seek_position;
4167 		}
4168 
4169 		session->ns_mover.md_w_index = n;
4170 	}
4171 
4172 	/*
4173 	 * The limit on the total amount of data to be sent can be
4174 	 * dictated by either the end of the mover window or the end of the
4175 	 * seek window.
4176 	 * First determine which window applies and then determine if the
4177 	 * send length needs to be less than a full record to avoid
4178 	 * exceeding the window.
4179 	 */
4180 	if (session->ns_mover.md_position +
4181 	    session->ns_mover.md_bytes_left_to_read >
4182 	    session->ns_mover.md_window_offset +
4183 	    session->ns_mover.md_window_length)
4184 		wlen = session->ns_mover.md_window_offset +
4185 		    session->ns_mover.md_window_length -
4186 		    session->ns_mover.md_position;
4187 	else
4188 		wlen = session->ns_mover.md_bytes_left_to_read;
4189 
4190 	NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
4191 
4192 	/*
4193 	 * Now limit the length to the amount of data in the buffer.
4194 	 */
4195 	if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
4196 		wlen = session->ns_mover.md_w_index -
4197 		    session->ns_mover.md_r_index;
4198 
4199 	len = wlen & 0xffffffff;
4200 	NDMP_LOG(LOG_DEBUG,
4201 	    "buffer restrictions: wlen %llu len %u", wlen, len);
4202 
4203 	/*
4204 	 * Write the data to the data connection.
4205 	 */
4206 	n = write(session->ns_mover.md_sock,
4207 	    &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
4208 
4209 	if (n < 0) {
4210 		if (errno == EWOULDBLOCK) {
4211 			NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
4212 			return;
4213 		}
4214 
4215 		NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
4216 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
4217 		return;
4218 	}
4219 
4220 	NDMP_LOG(LOG_DEBUG,
4221 	    "wrote %u of %u bytes to data connection position %llu r_index %lu",
4222 	    n, len, session->ns_mover.md_position,
4223 	    session->ns_mover.md_r_index);
4224 
4225 	session->ns_mover.md_r_index += n;
4226 	session->ns_mover.md_position += n;
4227 	session->ns_mover.md_bytes_left_to_read -= n;
4228 
4229 	/*
4230 	 * If all data in the buffer has been written,
4231 	 * zero the buffer indices. The next call to this function
4232 	 * will read more data from the tape device into the buffer.
4233 	 */
4234 	if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
4235 		session->ns_mover.md_r_index = 0;
4236 		session->ns_mover.md_w_index = 0;
4237 	}
4238 
4239 	/*
4240 	 * If the read limit has been reached,
4241 	 * then remove the file handler to prevent this
4242 	 * function from getting called. The next mover_read request
4243 	 * will reinstall the handler.
4244 	 */
4245 	if (session->ns_mover.md_bytes_left_to_read == 0)
4246 		(void) ndmpd_remove_file_handler(session, fd);
4247 }
4248 
4249 
4250 /*
4251  * accept_connection_v3
4252  *
4253  * Accept a data connection from a data server.
4254  * Called by ndmpd_select when a connection is pending on
4255  * the mover listen socket.
4256  *
4257  * Parameters:
4258  *   cookie  (input) - session pointer.
4259  *   fd      (input) - file descriptor.
4260  *   mode    (input) - select mode.
4261  *
4262  * Returns:
4263  *   void.
4264  */
4265 /*ARGSUSED*/
4266 static void
4267 accept_connection_v3(void *cookie, int fd, ulong_t mode)
4268 {
4269 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
4270 	int from_len;
4271 	struct sockaddr_in from;
4272 	int flag = 1;
4273 
4274 	from_len = sizeof (from);
4275 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
4276 	    &from_len);
4277 
4278 	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
4279 	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
4280 
4281 	(void) ndmpd_remove_file_handler(session, fd);
4282 	(void) close(session->ns_mover.md_listen_sock);
4283 	session->ns_mover.md_listen_sock = -1;
4284 
4285 	if (session->ns_mover.md_sock < 0) {
4286 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
4287 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
4288 		return;
4289 	}
4290 
4291 	/*
4292 	 * Save the peer address.
4293 	 */
4294 	session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
4295 	session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
4296 
4297 	/*
4298 	 * Set the parameter of the new socket.
4299 	 */
4300 	(void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE,
4301 	    &flag, sizeof (flag));
4302 
4303 	ndmp_set_socket_nodelay(session->ns_mover.md_sock);
4304 	if (ndmp_sbs > 0)
4305 		ndmp_set_socket_snd_buf(session->ns_mover.md_sock,
4306 		    ndmp_sbs*KILOBYTE);
4307 	if (ndmp_rbs > 0)
4308 		ndmp_set_socket_rcv_buf(session->ns_mover.md_sock,
4309 		    ndmp_rbs*KILOBYTE);
4310 
4311 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
4312 
4313 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
4314 		if (ndmpd_add_file_handler(session, (void*)session,
4315 		    session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
4316 		    HC_MOVER, mover_data_read_v3) < 0) {
4317 			ndmpd_mover_error(session,
4318 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
4319 			return;
4320 		}
4321 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
4322 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4323 		    ntohs(from.sin_port));
4324 	} else {
4325 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
4326 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4327 		    ntohs(from.sin_port));
4328 	}
4329 
4330 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
4331 }
4332 
4333 
4334 /*
4335  * create_listen_socket_v3
4336  *
4337  * Creates a socket for listening for accepting data connections.
4338  *
4339  * Parameters:
4340  *   session (input)  - session pointer.
4341  *   addr    (output) - location to store address of socket.
4342  *   port    (output) - location to store port of socket.
4343  *
4344  * Returns:
4345  *   0 - success.
4346  *  -1 - error.
4347  */
4348 static int
4349 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
4350 {
4351 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
4352 	if (session->ns_mover.md_listen_sock < 0)
4353 		return (-1);
4354 
4355 	/*
4356 	 * Add a file handler for the listen socket.
4357 	 * ndmpd_select will call accept_connection when a
4358 	 * connection is ready to be accepted.
4359 	 */
4360 	if (ndmpd_add_file_handler(session, (void *) session,
4361 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
4362 	    accept_connection_v3) < 0) {
4363 		(void) close(session->ns_mover.md_listen_sock);
4364 		session->ns_mover.md_listen_sock = -1;
4365 		return (-1);
4366 	}
4367 	NDMP_LOG(LOG_DEBUG, "IP %s port %d",
4368 	    inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
4369 	return (0);
4370 }
4371 
4372 
4373 /*
4374  * mover_connect_sock_v3
4375  *
4376  * Connect the mover to the specified address
4377  *
4378  * Parameters:
4379  *   session (input)  - session pointer.
4380  *   mode    (input)  - mover mode.
4381  *   addr    (output) - location to store address of socket.
4382  *   port    (output) - location to store port of socket.
4383  *
4384  * Returns:
4385  *   error code.
4386  */
4387 static ndmp_error
4388 mover_connect_sock_v3(ndmpd_session_t *session, ndmp_mover_mode mode,
4389     ulong_t addr, ushort_t port)
4390 {
4391 	int sock;
4392 
4393 	sock = ndmp_connect_sock_v3(addr, port);
4394 	if (sock < 0)
4395 		return (NDMP_CONNECT_ERR);
4396 
4397 	if (mode == NDMP_MOVER_MODE_READ) {
4398 		if (ndmpd_add_file_handler(session, (void*)session, sock,
4399 		    NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
4400 			(void) close(sock);
4401 			return (NDMP_CONNECT_ERR);
4402 		}
4403 	}
4404 	session->ns_mover.md_sock = sock;
4405 	session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
4406 	session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
4407 	session->ns_mover.md_data_addr.tcp_port_v3 = port;
4408 	return (NDMP_NO_ERR);
4409 }
4410 
4411 
4412 /*
4413  * ndmpd_local_read_v3
4414  *
4415  * Reads data from the local tape device.
4416  * Full tape records are read and buffered.
4417  *
4418  * Parameters:
4419  *   session (input) - session pointer.
4420  *   data    (input) - location to store data.
4421  *   length  (input) - data length.
4422  *
4423  * Returns:
4424  *   1 - no read error but no writer running
4425  *   0 - data successfully read.
4426  *  -1 - error.
4427  */
4428 int
4429 ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
4430 {
4431 	ulong_t count;
4432 	ulong_t len;
4433 	ssize_t n;
4434 
4435 	count = 0;
4436 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
4437 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
4438 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
4439 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
4440 		return (-1);
4441 	}
4442 
4443 	/*
4444 	 * Automatically increase the seek window if necessary.
4445 	 * This is needed in the event the module attempts to read
4446 	 * past a seek window set via a prior call to ndmpd_seek() or
4447 	 * the module has not issued a seek. If no seek was issued then
4448 	 * pretend that a seek was issued to read the entire tape.
4449 	 */
4450 	if (length > session->ns_mover.md_bytes_left_to_read) {
4451 		/* ndmpd_seek() never called? */
4452 		if (session->ns_data.dd_read_length == 0) {
4453 			session->ns_mover.md_bytes_left_to_read = ~0LL;
4454 			session->ns_data.dd_read_offset = 0LL;
4455 			session->ns_data.dd_read_length = ~0LL;
4456 		} else {
4457 			session->ns_mover.md_bytes_left_to_read = length;
4458 			session->ns_data.dd_read_offset =
4459 			    session->ns_mover.md_position;
4460 			session->ns_data.dd_read_length = length;
4461 		}
4462 	}
4463 
4464 	/*
4465 	 * Read as many records as necessary to satisfy the request.
4466 	 */
4467 	while (count < length) {
4468 		/*
4469 		 * If the end of the mover window has been reached,
4470 		 * then notify the client that a new data window is needed.
4471 		 */
4472 		if (session->ns_mover.md_position >=
4473 		    session->ns_mover.md_window_offset +
4474 		    session->ns_mover.md_window_length) {
4475 			if (mover_pause_v3(session,
4476 			    NDMP_MOVER_PAUSE_SEEK) < 0) {
4477 				ndmpd_mover_error(session,
4478 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
4479 				return (-1);
4480 			}
4481 			continue;
4482 		}
4483 
4484 		len = length - count;
4485 
4486 		/*
4487 		 * Prevent reading past the end of the window.
4488 		 */
4489 		if (len > session->ns_mover.md_window_offset +
4490 		    session->ns_mover.md_window_length -
4491 		    session->ns_mover.md_position)
4492 			len = session->ns_mover.md_window_offset +
4493 			    session->ns_mover.md_window_length -
4494 			    session->ns_mover.md_position;
4495 
4496 		/*
4497 		 * Copy from the data buffer first.
4498 		 */
4499 		if (session->ns_mover.md_w_index -
4500 		    session->ns_mover.md_r_index != 0) {
4501 			/*
4502 			 * Limit the copy to the amount of data in the buffer.
4503 			 */
4504 			if (len > session->ns_mover.md_w_index -
4505 			    session->ns_mover.md_r_index)
4506 				len = session->ns_mover.md_w_index -
4507 				    session->ns_mover.md_r_index;
4508 			(void) memcpy((void*)&data[count],
4509 			    &session->ns_mover.md_buf[session->
4510 			    ns_mover.md_r_index], len);
4511 			count += len;
4512 			session->ns_mover.md_r_index += len;
4513 			session->ns_mover.md_bytes_left_to_read -= len;
4514 			session->ns_mover.md_position += len;
4515 			continue;
4516 		}
4517 
4518 		/*
4519 		 * Determine if data needs to be buffered or
4520 		 * can be read directly to user supplied location.
4521 		 * We can fast path the read if at least a full record
4522 		 * needs to be read and there is no seek pending.
4523 		 * This is done to eliminate a buffer copy.
4524 		 */
4525 		if (len >= session->ns_mover.md_record_size &&
4526 		    session->ns_mover.md_position >=
4527 		    session->ns_mover.md_seek_position) {
4528 			n = mover_tape_read_v3(session, &data[count]);
4529 			if (n <= 0) {
4530 				if (n == TAPE_NO_WRITER_ERR)
4531 					return (1);
4532 
4533 				ndmpd_mover_error(session,
4534 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4535 				    NDMP_MOVER_HALT_MEDIA_ERROR));
4536 				return ((n == 0) ? 1 : -1);
4537 			}
4538 
4539 			count += n;
4540 			session->ns_mover.md_bytes_left_to_read -= n;
4541 			session->ns_mover.md_position += n;
4542 			continue;
4543 		}
4544 
4545 		/* Read the next record into the buffer. */
4546 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4547 		if (n <= 0) {
4548 			if (n == TAPE_NO_WRITER_ERR)
4549 				return (1);
4550 
4551 			ndmpd_mover_error(session,
4552 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4553 			    NDMP_MOVER_HALT_MEDIA_ERROR));
4554 			return ((n == 0) ? 1 : -1);
4555 		}
4556 
4557 		session->ns_mover.md_w_index = n;
4558 		session->ns_mover.md_r_index = 0;
4559 
4560 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
4561 
4562 		/*
4563 		 * Discard data if the current data stream position is
4564 		 * prior to the seek position. This is necessary if a seek
4565 		 * request set the seek pointer to a position that is not a
4566 		 * record boundary. The seek request handler can only position
4567 		 * to the start of a record.
4568 		 */
4569 		if (session->ns_mover.md_position <
4570 		    session->ns_mover.md_seek_position) {
4571 			session->ns_mover.md_r_index =
4572 			    session->ns_mover.md_seek_position -
4573 			    session->ns_mover.md_position;
4574 			session->ns_mover.md_position =
4575 			    session->ns_mover.md_seek_position;
4576 		}
4577 	}
4578 
4579 	return (0);
4580 }
4581