1/*
2 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5/*
6 * BSD 3 Clause License
7 *
8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 	- Redistributions of source code must retain the above copyright
14 *	  notice, this list of conditions and the following disclaimer.
15 *
16 * 	- Redistributions in binary form must reproduce the above copyright
17 *	  notice, this list of conditions and the following disclaimer in
18 *	  the documentation and/or other materials provided with the
19 *	  distribution.
20 *
21 *	- Neither the name of The Storage Networking Industry Association (SNIA)
22 *	  nor the names of its contributors may be used to endorse or promote
23 *	  products derived from this software without specific prior written
24 *	  permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38/* Copyright (c) 2007, The Storage Networking Industry Association. */
39/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40/* Copyright 2014 Nexenta Systems, Inc.  All rights reserved. */
41
42#include <sys/param.h>
43#include <fcntl.h>
44#include <sys/mtio.h>
45#include <errno.h>
46#include <stdio.h>
47#include <string.h>
48#include <unistd.h>
49#include "ndmpd_common.h"
50#include "ndmpd.h"
51
52static void tape_open_send_reply(ndmp_connection_t *connection, int err);
53static void unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
54    ndmp_tape_read_reply *reply);
55static boolean_t validmode(int mode);
56static void common_tape_open(ndmp_connection_t *connection, char *devname,
57    int ndmpmode);
58static void common_tape_close(ndmp_connection_t *connection);
59
60/*
61 * Configurable delay & time when the tape is
62 * busy during opening the tape.
63 */
64int ndmp_tape_open_retries = 5;
65int ndmp_tape_open_delay = 1000;
66
67/*
68 * A few words about EOT (end-of-tape) and EOM handling on tapes with SVR4
69 * semantic:
70 *
71 * We adhere to terminology as used in st driver.  EOT means end of recorded
72 * data on a tape. This is different from EOM (somewhere referred to as LEOT)
73 * which is the end of tape medium. EOT is meaningful only for reads while EOM
74 * is meaningful only for writes. It's not possible to read after EOT (fails
75 * with EIO), but it's possible to write data after EOM. EOM returned by st
76 * driver on modern tape drives is just indication that the physical end of
77 * tape medium is nearing and that writer should write just the necessary
78 * minimum and stop writing. When physical end of tape is reached all writes
79 * return EIO. If EOM is crossed during read operation then st driver doesn't
80 * bother to report it to client and that's alright because reads don't care
81 * where medium physically ends but they care about meaningful data recorded on
82 * the tape and as long as there are such data reads should continue to work.
83 *
84 * When reading EOT is signalled by st driver by two empty consecutive reads
85 * (with FSF done between them).  When writing EOM is signalled by empty write
86 * (a write which writes zero bytes). Following writes succeed until physical
87 * end of tape is reached in which case EIO is returned.
88 */
89
90/*
91 * ************************************************************************
92 * NDMP V2 HANDLERS
93 * ************************************************************************
94 */
95
96/*
97 * ndmpd_tape_open_v2
98 *
99 * This handler opens the specified tape device.
100 *
101 * Parameters:
102 *   connection (input) - connection handle.
103 *   body       (input) - request message body.
104 *
105 * Returns:
106 *   void
107 */
108void
109ndmpd_tape_open_v2(ndmp_connection_t *connection, void *body)
110{
111	ndmp_tape_open_request_v2 *request = (ndmp_tape_open_request_v2 *) body;
112	ndmpd_session_t *session = ndmp_get_client_data(connection);
113	char adptnm[SCSI_MAX_NAME];
114	int mode;
115	int sid, lun;
116	int err;
117	scsi_adapter_t *sa;
118	int devid;
119
120	err = NDMP_NO_ERR;
121
122	if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
123		NDMP_LOG(LOG_INFO,
124		    "Connection already has a tape or scsi device open");
125		err = NDMP_DEVICE_OPENED_ERR;
126	} else if (request->mode != NDMP_TAPE_READ_MODE &&
127	    request->mode != NDMP_TAPE_WRITE_MODE &&
128	    request->mode != NDMP_TAPE_RAW1_MODE) {
129		err = NDMP_ILLEGAL_ARGS_ERR;
130	}
131
132	if ((sa = scsi_get_adapter(0)) != NULL) {
133		NDMP_LOG(LOG_DEBUG,
134		    "Adapter device opened: %s", request->device.name);
135		(void) strlcpy(adptnm, request->device.name, SCSI_MAX_NAME-2);
136		adptnm[SCSI_MAX_NAME-1] = '\0';
137		sid = lun = -1;
138	}
139	/* try to get the scsi id etc.... */
140	if (sa) {
141		scsi_find_sid_lun(sa, request->device.name, &sid, &lun);
142		if (ndmp_open_list_find(request->device.name, sid, lun) == 0 &&
143		    (devid = tape_open(request->device.name,
144		    O_RDWR | O_NDELAY)) < 0) {
145			NDMP_LOG(LOG_ERR, "Failed to open device %s: %m.",
146			    request->device.name);
147			err = NDMP_NO_DEVICE_ERR;
148		}
149		else
150			(void) close(devid);
151	} else {
152		NDMP_LOG(LOG_ERR, "%s: No such tape device.",
153		    request->device.name);
154		err = NDMP_NO_DEVICE_ERR;
155	}
156	if (err != NDMP_NO_ERR) {
157		tape_open_send_reply(connection, err);
158		return;
159	}
160
161	switch (ndmp_open_list_add(connection, adptnm, sid, lun, devid)) {
162	case 0:
163		err = NDMP_NO_ERR;
164		break;
165	case EBUSY:
166		err = NDMP_DEVICE_BUSY_ERR;
167		break;
168	case ENOMEM:
169		err = NDMP_NO_MEM_ERR;
170		break;
171	default:
172		err = NDMP_IO_ERR;
173	}
174	if (err != NDMP_NO_ERR) {
175		tape_open_send_reply(connection, err);
176		return;
177	}
178
179	/*
180	 * According to Connectathon 2001, the 0x7fffffff is a secret
181	 * code between "Workstartion Solutions" and * net_app.
182	 * If mode is set to this value, tape_open() won't fail if
183	 * the tape device is not ready.
184	 */
185	if (request->mode != NDMP_TAPE_RAW1_MODE &&
186	    !is_tape_unit_ready(adptnm, 0)) {
187		(void) ndmp_open_list_del(adptnm, sid, lun);
188		tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
189		return;
190	}
191
192	mode = (request->mode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
193	mode |= O_NDELAY;
194	if ((session->ns_tape.td_fd = open(request->device.name, mode)) < 0) {
195			NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
196			    request->device.name);
197			switch (errno) {
198			case EACCES:
199				err = NDMP_WRITE_PROTECT_ERR;
200				break;
201			case ENXIO:
202			case ENOENT:
203				err = NDMP_NO_DEVICE_ERR;
204				break;
205			case EBUSY:
206				err = NDMP_DEVICE_BUSY_ERR;
207				break;
208			default:
209				err = NDMP_IO_ERR;
210			}
211
212			(void) ndmp_open_list_del(adptnm, sid, lun);
213			tape_open_send_reply(connection, err);
214			return;
215		}
216
217	session->ns_tape.td_mode = request->mode;
218	session->ns_tape.td_sid = sid;
219	session->ns_tape.td_lun = lun;
220	(void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
221	session->ns_tape.td_record_count = 0;
222
223	NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
224
225	tape_open_send_reply(connection, NDMP_NO_ERR);
226}
227
228
229/*
230 * ndmpd_tape_close_v2
231 *
232 * This handler closes the currently open tape device.
233 *
234 * Parameters:
235 *   connection (input) - connection handle.
236 *   body       (input) - request message body.
237 *
238 * Returns:
239 *   void
240 */
241/*ARGSUSED*/
242void
243ndmpd_tape_close_v2(ndmp_connection_t *connection, void *body)
244{
245	ndmp_tape_close_reply reply;
246	ndmpd_session_t *session = ndmp_get_client_data(connection);
247
248	if (session->ns_tape.td_fd == -1) {
249		NDMP_LOG(LOG_ERR, "Tape device is not open.");
250		reply.error = NDMP_DEV_NOT_OPEN_ERR;
251		ndmp_send_reply(connection, (void *) &reply,
252		    "sending tape_close reply");
253		return;
254	}
255	common_tape_close(connection);
256
257}
258
259/*
260 * ndmpd_tape_get_state_v2
261 *
262 * This handler handles the tape_get_state request.
263 * Status information for the currently open tape device is returned.
264 *
265 * Parameters:
266 *   connection (input) - connection handle.
267 *   body       (input) - request message body.
268 *
269 * Returns:
270 *   void
271 */
272/*ARGSUSED*/
273void
274ndmpd_tape_get_state_v2(ndmp_connection_t *connection, void *body)
275
276{
277	ndmp_tape_get_state_reply_v2 reply;
278	ndmpd_session_t *session = ndmp_get_client_data(connection);
279	struct mtget mtstatus;
280	struct mtdrivetype_request dtpr;
281	struct mtdrivetype dtp;
282
283	if (session->ns_tape.td_fd == -1) {
284		NDMP_LOG(LOG_ERR, "Tape device is not open.");
285		reply.error = NDMP_DEV_NOT_OPEN_ERR;
286		ndmp_send_reply(connection, (void *) &reply,
287		    "sending tape_get_state reply");
288		return;
289	}
290
291	if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) < 0) {
292		NDMP_LOG(LOG_ERR, "Failed to get status from tape: %m.");
293		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
294		reply.error = NDMP_IO_ERR;
295		ndmp_send_reply(connection, (void *)&reply,
296		    "sending tape_get_state reply");
297		return;
298	}
299
300	dtpr.size = sizeof (struct mtdrivetype);
301	dtpr.mtdtp = &dtp;
302	if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
303		NDMP_LOG(LOG_ERR,
304		    "Failed to get drive type information from tape: %m.");
305		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
306		reply.error = NDMP_IO_ERR;
307		ndmp_send_reply(connection, (void *)&reply,
308		    "sending tape_get_state reply");
309		return;
310	}
311
312	reply.flags = 0;
313
314	reply.file_num = mtstatus.mt_fileno;
315	reply.soft_errors = 0;
316	reply.block_size = dtp.bsize;
317	if (dtp.bsize == 0)
318		reply.blockno = mtstatus.mt_blkno;
319	else
320		reply.blockno = mtstatus.mt_blkno *
321		    (session->ns_mover.md_record_size / dtp.bsize);
322
323	reply.soft_errors = 0;
324	reply.total_space = long_long_to_quad(0);	/* not supported */
325	reply.space_remain = long_long_to_quad(0);	/* not supported */
326
327	NDMP_LOG(LOG_DEBUG,
328	    "flags: 0x%x, file_num: %d, block_size: %d, blockno: %d",
329	    reply.flags, reply.file_num, reply.block_size, reply.blockno);
330
331	reply.error = NDMP_NO_ERR;
332	ndmp_send_reply(connection, (void *) &reply,
333	    "sending tape_get_state reply");
334}
335
336
337/*
338 * ndmpd_tape_mtio_v2
339 *
340 * This handler handles tape_mtio requests.
341 *
342 * Parameters:
343 *   connection (input) - connection handle.
344 *   body       (input) - request message body.
345 *
346 * Returns:
347 *   void
348 */
349void
350ndmpd_tape_mtio_v2(ndmp_connection_t *connection, void *body)
351{
352	ndmp_tape_mtio_request *request = (ndmp_tape_mtio_request *) body;
353	ndmp_tape_mtio_reply reply;
354	ndmpd_session_t *session = ndmp_get_client_data(connection);
355
356	struct mtop tapeop;
357	struct mtget mtstatus;
358	int retry = 0;
359	int rc;
360
361	reply.resid_count = 0;
362
363	if (session->ns_tape.td_fd == -1) {
364		NDMP_LOG(LOG_ERR, "Tape device is not open.");
365		reply.error = NDMP_DEV_NOT_OPEN_ERR;
366		ndmp_send_reply(connection, (void *) &reply,
367		    "sending tape_mtio reply");
368		return;
369	}
370
371	reply.error = NDMP_NO_ERR;
372	switch (request->tape_op) {
373	case NDMP_MTIO_FSF:
374		tapeop.mt_op = MTFSF;
375		break;
376	case NDMP_MTIO_BSF:
377		tapeop.mt_op = MTBSF;
378		break;
379	case NDMP_MTIO_FSR:
380		tapeop.mt_op = MTFSR;
381		break;
382	case NDMP_MTIO_BSR:
383		tapeop.mt_op = MTBSR;
384		break;
385	case NDMP_MTIO_REW:
386		tapeop.mt_op = MTREW;
387		break;
388	case NDMP_MTIO_EOF:
389		if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE)
390			reply.error = NDMP_PERMISSION_ERR;
391		tapeop.mt_op = MTWEOF;
392		break;
393	case NDMP_MTIO_OFF:
394		tapeop.mt_op = MTOFFL;
395		break;
396
397	case NDMP_MTIO_TUR: /* test unit ready */
398
399		if (is_tape_unit_ready(session->ns_tape.td_adapter_name,
400		    session->ns_tape.td_fd) == 0)
401			/* tape not ready ? */
402			reply.error = NDMP_NO_TAPE_LOADED_ERR;
403		break;
404
405	default:
406		reply.error = NDMP_ILLEGAL_ARGS_ERR;
407	}
408
409	if (reply.error == NDMP_NO_ERR && request->tape_op != NDMP_MTIO_TUR) {
410		tapeop.mt_count = request->count;
411
412		do {
413			NS_UPD(twait, trun);
414			errno = 0;
415			rc = ioctl(session->ns_tape.td_fd, MTIOCTOP, &tapeop);
416			NS_UPD(trun, twait);
417			NDMP_LOG(LOG_DEBUG,
418			    "ioctl MTIO rc:%d, cmd:%d, retry:%d, error: %d",
419			    rc, tapeop.mt_op, retry, errno);
420		} while (rc < 0 && errno == EIO &&
421		    retry++ < 5);
422
423		/*
424		 * Ignore I/O errors since these usually are the result of
425		 * attempting to position past the beginning or end of the tape.
426		 * The residual count will be returned and can be used to
427		 * determine that the call was not completely successful.
428		 */
429		if (rc < 0) {
430			NDMP_LOG(LOG_ERR,
431			    "Failed to send command to tape: %m.");
432			NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCTOP) error: %m.");
433
434			/* MTWEOF doesnt have residual count */
435			if (tapeop.mt_op == MTWEOF)
436				reply.error = NDMP_IO_ERR;
437			else
438				reply.error = NDMP_NO_ERR;
439			reply.resid_count = tapeop.mt_count;
440			ndmp_send_reply(connection, (void *)&reply,
441			    "sending tape_mtio reply");
442			return;
443		}
444
445		if (request->tape_op != NDMP_MTIO_REW &&
446		    request->tape_op != NDMP_MTIO_OFF) {
447			if (ioctl(session->ns_tape.td_fd, MTIOCGET,
448			    &mtstatus) < 0) {
449				NDMP_LOG(LOG_ERR,
450				    "Failed to send command to tape: %m.");
451				NDMP_LOG(LOG_DEBUG,
452				    "ioctl(MTIOCGET) error: %m.");
453				reply.error = NDMP_IO_ERR;
454				ndmp_send_reply(connection, (void *)&reply,
455				    "sending tape_mtio reply");
456
457				return;
458			}
459
460			reply.resid_count = labs(mtstatus.mt_resid);
461		}
462	}
463
464	NDMP_LOG(LOG_DEBUG, "resid_count: %d",
465	    reply.resid_count);
466	ndmp_send_reply(connection, (void *) &reply, "sending tape_mtio reply");
467}
468
469
470/*
471 * ndmpd_tape_read_v2
472 *
473 * This handler handles tape_read requests.
474 * This interface is a non-buffered interface. Each read request
475 * maps directly to a read to the tape device. It is the responsibility
476 * of the NDMP client to issue read requests with a length that is at
477 * least as large as the record size used write the tape. The tape driver
478 * always reads a full record. Data is discarded if the read request is
479 * smaller than the record size.
480 * It is the responsibility of the NDMP client to ensure that the
481 * length is a multiple of the tape block size if the tape device
482 * is in fixed block mode.
483 *
484 * Parameters:
485 *   connection (input) - connection handle.
486 *   body       (input) - request message body.
487 *
488 * Returns:
489 *   void
490 */
491void
492ndmpd_tape_read_v2(ndmp_connection_t *connection, void *body)
493{
494	ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
495	ndmp_tape_read_reply reply;
496	ndmpd_session_t *session = ndmp_get_client_data(connection);
497	char *buf;
498
499	reply.data_in.data_in_len = 0;
500
501	if (session->ns_tape.td_fd == -1) {
502		NDMP_LOG(LOG_ERR, "Tape device is not open.");
503		reply.error = NDMP_DEV_NOT_OPEN_ERR;
504		ndmp_send_reply(connection, (void *)&reply,
505		    "sending tape_read reply");
506		return;
507	}
508	if (request->count == 0) {
509		reply.error = NDMP_NO_ERR;
510		ndmp_send_reply(connection, (void *)&reply,
511		    "sending tape_read reply");
512		return;
513	}
514	if ((buf = ndmp_malloc(request->count)) == 0) {
515		reply.error = NDMP_NO_MEM_ERR;
516		ndmp_send_reply(connection, (void *)&reply,
517		    "sending tape_read reply");
518		return;
519	}
520
521	unbuffered_read(session, buf, request->count, &reply);
522
523	ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
524	(void) free(buf);
525}
526
527
528/*
529 * ndmpd_tape_execute_cdb_v2
530 *
531 * This handler handles tape_execute_cdb requests.
532 *
533 * Parameters:
534 *   connection (input) - connection handle.
535 *   body       (input) - request message body.
536 *
537 * Returns:
538 *   void
539 */
540void
541ndmpd_tape_execute_cdb_v2(ndmp_connection_t *connection, void *body)
542{
543	ndmp_tape_execute_cdb_request *request;
544	ndmp_tape_execute_cdb_reply reply;
545	ndmpd_session_t *session = ndmp_get_client_data(connection);
546
547	request = (ndmp_tape_execute_cdb_request *) body;
548
549	if (session->ns_tape.td_fd == -1) {
550		(void) memset((void *) &reply, 0, sizeof (reply));
551
552		NDMP_LOG(LOG_ERR, "Tape device is not open.");
553		reply.error = NDMP_DEV_NOT_OPEN_ERR;
554		ndmp_send_reply(connection, (void *) &reply,
555		    "sending tape_execute_cdb reply");
556	} else {
557		ndmp_execute_cdb(session, session->ns_tape.td_adapter_name,
558		    session->ns_tape.td_sid, session->ns_tape.td_lun,
559		    (ndmp_execute_cdb_request *)request);
560	}
561}
562
563
564/*
565 * ************************************************************************
566 * NDMP V3 HANDLERS
567 * ************************************************************************
568 */
569
570/*
571 * ndmpd_tape_open_v3
572 *
573 * This handler opens the specified tape device.
574 *
575 * Parameters:
576 *   connection (input) - connection handle.
577 *   body       (input) - request message body.
578 *
579 * Returns:
580 *   void
581 */
582void
583ndmpd_tape_open_v3(ndmp_connection_t *connection, void *body)
584{
585	ndmp_tape_open_request_v3 *request = (ndmp_tape_open_request_v3 *)body;
586
587	common_tape_open(connection, request->device, request->mode);
588}
589
590
591/*
592 * ndmpd_tape_get_state_v3
593 *
594 * This handler handles the ndmp_tape_get_state_request.
595 * Status information for the currently open tape device is returned.
596 *
597 * Parameters:
598 *   connection (input) - connection handle.
599 *   body       (input) - request message body.
600 *
601 * Returns:
602 *   void
603 */
604/*ARGSUSED*/
605void
606ndmpd_tape_get_state_v3(ndmp_connection_t *connection, void *body)
607{
608	ndmp_tape_get_state_reply_v3 reply;
609	ndmpd_session_t *session = ndmp_get_client_data(connection);
610	struct mtdrivetype_request dtpr;
611	struct mtdrivetype dtp;
612	struct mtget mtstatus;
613
614	if (session->ns_tape.td_fd == -1) {
615		NDMP_LOG(LOG_ERR, "Tape device is not open.");
616		reply.error = NDMP_DEV_NOT_OPEN_ERR;
617		ndmp_send_reply(connection, (void *) &reply,
618		    "sending tape_get_state reply");
619		return;
620	}
621
622	if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
623		NDMP_LOG(LOG_ERR, "Failed to get status from tape: %m.");
624		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
625
626		reply.error = NDMP_IO_ERR;
627		ndmp_send_reply(connection, (void *)&reply,
628		    "sending tape_get_state reply");
629		return;
630	}
631
632	dtpr.size = sizeof (struct mtdrivetype);
633	dtpr.mtdtp = &dtp;
634	if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
635		NDMP_LOG(LOG_ERR,
636		    "Failed to get drive type information from tape: %m.");
637		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
638
639		reply.error = NDMP_IO_ERR;
640		ndmp_send_reply(connection, (void *)&reply,
641		    "sending tape_get_state reply");
642		return;
643	}
644
645	reply.flags = 0;
646
647	reply.file_num = mtstatus.mt_fileno;
648	reply.soft_errors = 0;
649	reply.block_size = dtp.bsize;
650	if (dtp.bsize == 0)
651		reply.blockno = mtstatus.mt_blkno;
652	else
653		reply.blockno = mtstatus.mt_blkno *
654		    (session->ns_mover.md_record_size / dtp.bsize);
655	reply.total_space = long_long_to_quad(0); /* not supported */
656	reply.space_remain = long_long_to_quad(0); /* not supported */
657	reply.partition = 0; /* not supported */
658
659	reply.soft_errors = 0;
660	reply.total_space = long_long_to_quad(0LL);
661	reply.space_remain = long_long_to_quad(0LL);
662
663	reply.invalid = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
664	    NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
665	    NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
666	    NDMP_TAPE_STATE_PARTITION_INVALID;
667
668
669	NDMP_LOG(LOG_DEBUG, "f 0x%x, fnum %d, bsize %d, bno: %d",
670	    reply.flags, reply.file_num, reply.block_size, reply.blockno);
671
672	reply.error = NDMP_NO_ERR;
673	ndmp_send_reply(connection, (void *) &reply,
674	    "sending tape_get_state reply");
675}
676
677/*
678 * tape_is_at_bot
679 *
680 * Returns 1 if tape is at BOT, 0 on error or not at BOT.
681 *
682 */
683int
684tape_is_at_bot(ndmpd_session_t *session)
685{
686	struct mtget mtstatus;
687
688	if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == 0 &&
689	    mtstatus.mt_fileno == 0 && mtstatus.mt_blkno == 0)
690		return (1);
691
692	return (0);
693}
694
695/*
696 * If we are at the beginning of a file (block # is zero) and read returns
697 * zero bytes then this has to be end of recorded data on the tape. Repeated
698 * reads at EOT return EIO. In both cases (zero read and EIO read) this
699 * function should be used to test if we are at EOT.
700 *
701 * Returns 1 if tape is at BOF, 0 on error or not at BOF.
702 */
703int
704tape_is_at_bof(ndmpd_session_t *session)
705{
706	struct mtget mtstatus;
707
708	if ((ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == 0) &&
709	    (mtstatus.mt_fileno > 0) && (mtstatus.mt_blkno == 0))
710		return (1);
711
712	return (0);
713}
714
715/*
716 * Skips forward over a file mark and then back before the file mark. Why is
717 * this needed? There are two reasons for it:
718 *
719 * 1) Because NDMPv4 spec requires that when EOF is encountered, the tape
720 * position should remain on BOT side of the file mark. When st driver reaches
721 * end of file get-position mtioctl reports position before file mark, however
722 * the file mark has already been read and the real position is thus after the
723 * file mark (real position as reported for example by uscsi commands). Thus we
724 * need to do FSF, which does nothing but only updates file & block counter in
725 * st driver and then BSF, which sets the position before the file mark. Thus
726 * current position as reported by scsi and mtioctl will be in sync.
727 *
728 * 2) st driver returns EIO for repeated reads at EOF while according to NDMP
729 * spec we should continue to return zero bytes until FSF is done. By skipping
730 * forward and backward, st driver will return zero bytes for the next read
731 * again and we don't need to specifically handle this case.
732 */
733void
734fm_dance(ndmpd_session_t *session)
735{
736	(void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
737	(void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
738}
739
740/*
741 * ndmpd_tape_write_v3
742 *
743 * This handler handles tape_write requests.  This interface is a non-buffered
744 * interface. Each write request maps directly to a write to the tape device.
745 * It is the responsibility of the NDMP client to pad the data to the desired
746 * record size.  It is the responsibility of the NDMP client to ensure that the
747 * length is a multiple of the tape block size if the tape device is in fixed
748 * block mode.
749 *
750 * A logical end of tape will return number of bytes written less than
751 * requested, and one more request to write will give 0 and NDMP_EOM_ERR,
752 * followed by NDMP_NO_ERR until NDMP_IO_ERR when physical end of tape is
753 * reached.
754 *
755 * Parameters:
756 *   connection (input) - connection handle.
757 *   body       (input) - request message body.
758 */
759void ndmpd_tape_write_v3(ndmp_connection_t *connection, void *body) {
760	ndmp_tape_write_request *request = (ndmp_tape_write_request *)body;
761	ndmp_tape_write_reply reply; ndmpd_session_t *session =
762		ndmp_get_client_data(connection); ssize_t n;
763
764	reply.count = 0;
765
766	if (session->ns_tape.td_fd == -1) {
767		NDMP_LOG(LOG_ERR, "Tape device is not open.");
768		reply.error = NDMP_DEV_NOT_OPEN_ERR;
769		ndmp_send_reply(connection, (void *) &reply,
770		    "sending tape_write reply");
771		return;
772	}
773	if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
774		NDMP_LOG(LOG_INFO, "Tape device opened in read-only mode");
775		reply.error = NDMP_PERMISSION_ERR;
776		ndmp_send_reply(connection, (void *) &reply,
777		    "sending tape_write reply");
778		return;
779	}
780	if (request->data_out.data_out_len == 0) {
781		reply.error = NDMP_NO_ERR;
782		ndmp_send_reply(connection, (void *) &reply,
783		    "sending tape_write reply");
784		return;
785	}
786
787	/*
788	 * V4 suggests that this should not be accepted
789	 * when mover is in listen or active state
790	 */
791	if (session->ns_protocol_version == NDMPV4 &&
792	    (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
793	    session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
794
795		reply.error = NDMP_DEVICE_BUSY_ERR;
796		ndmp_send_reply(connection, (void *) &reply,
797		    "sending tape_write reply");
798		return;
799	}
800
801	n = write(session->ns_tape.td_fd, request->data_out.data_out_val,
802	    request->data_out.data_out_len);
803
804	if (n < 0) {
805		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
806		reply.error = NDMP_IO_ERR;
807	} else if (n == 0) {
808		NDMP_LOG(LOG_INFO, "EOM detected");
809		reply.error = NDMP_EOM_ERR;
810	} else {
811		NS_ADD(wtape, n);
812		reply.count = n;
813		reply.error = NDMP_NO_ERR;
814
815		if (n < request->data_out.data_out_len)
816			NDMP_LOG(LOG_DEBUG,
817				"EOM is coming (partial write of %d bytes)", n);
818	}
819
820	ndmp_send_reply(connection, (void *) &reply,
821	    "sending tape_write reply");
822}
823
824/*
825 * ndmpd_tape_read_v3
826 *
827 * This handler handles tape_read requests.  This interface is a non-buffered
828 * interface. Each read request maps directly to a read to the tape device. It
829 * is the responsibility of the NDMP client to issue read requests with a
830 * length that is at least as large as the record size used write the tape. The
831 * tape driver always reads a full record. Data is discarded if the read
832 * request is smaller than the record size.  It is the responsibility of the
833 * NDMP client to ensure that the length is a multiple of the tape block size
834 * if the tape device is in fixed block mode.
835 *
836 * A logical end of tape will return less bytes than requested, and one more
837 * request to read will give 0 and NDMP_EOM_ERR.  All subsequent reads will
838 * return NDMP_EOM_ERR until the tape is repositioned.
839 *
840 * Parameters:
841 *   connection (input) - connection handle.
842 *   body       (input) - request message body.
843 */
844void
845ndmpd_tape_read_v3(ndmp_connection_t *connection, void *body)
846{
847	ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
848	ndmp_tape_read_reply reply;
849	ndmpd_session_t *session = ndmp_get_client_data(connection);
850	char *buf;
851	int n;
852
853	reply.data_in.data_in_len = 0;
854
855	if (session->ns_tape.td_fd == -1) {
856		NDMP_LOG(LOG_ERR, "Tape device is not open.");
857		reply.error = NDMP_DEV_NOT_OPEN_ERR;
858		ndmp_send_reply(connection, (void *) &reply,
859		    "sending tape_read reply");
860		return;
861	}
862	if (request->count == 0) {
863		reply.error = NDMP_NO_ERR;
864		ndmp_send_reply(connection, (void *) &reply,
865		    "sending tape_read reply");
866		return;
867	}
868
869	/*
870	 * V4 suggests that this should not be accepted
871	 * when mover is in listen or active state
872	 */
873	if (session->ns_protocol_version == NDMPV4 &&
874	    (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
875	    session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
876
877		reply.error = NDMP_DEVICE_BUSY_ERR;
878		ndmp_send_reply(connection, (void *) &reply,
879		    "sending tape_read reply");
880		return;
881	}
882
883	if ((buf = ndmp_malloc(request->count)) == NULL) {
884		reply.error = NDMP_NO_MEM_ERR;
885		ndmp_send_reply(connection, (void *) &reply,
886		    "sending tape_read reply");
887		return;
888	}
889
890	n = read(session->ns_tape.td_fd, buf, request->count);
891	if (n < 0) {
892		/*
893		 * This fix is for Symantec during importing
894		 * of spanned data between the tapes.
895		 */
896		if (errno == ENOSPC) {
897			reply.error = NDMP_EOF_ERR;
898		}
899		/*
900		 * If at beginning of file and read fails with EIO, then it's
901		 * repeated attempt to read at EOT.
902		 */
903		else if (errno == EIO && tape_is_at_bof(session)) {
904			NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
905			reply.error = NDMP_EOM_ERR;
906		}
907		/*
908		 * According to NDMPv4 spec preferred error code when
909		 * trying to read from blank tape is NDMP_EOM_ERR.
910		 */
911		else if (errno == EIO && tape_is_at_bot(session)) {
912			NDMP_LOG(LOG_ERR, "Blank tape detected, returning EOM");
913			reply.error = NDMP_EOM_ERR;
914		} else {
915			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
916			reply.error = NDMP_IO_ERR;
917		}
918	} else if (n == 0) {
919		if (tape_is_at_bof(session)) {
920			NDMP_LOG(LOG_DEBUG, "EOT detected");
921			reply.error = NDMP_EOM_ERR;
922		} else {
923			/* reposition the tape to BOT side of FM */
924			fm_dance(session);
925			NDMP_LOG(LOG_DEBUG, "EOF detected");
926			reply.error = NDMP_EOF_ERR;
927		}
928	} else {
929		session->ns_tape.td_pos += n;
930		reply.data_in.data_in_len = n;
931		reply.data_in.data_in_val = buf;
932		reply.error = NDMP_NO_ERR;
933		NS_ADD(rtape, n);
934	}
935
936	ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
937	free(buf);
938}
939
940
941/*
942 * ************************************************************************
943 * NDMP V4 HANDLERS
944 * ************************************************************************
945 */
946
947/*
948 * ndmpd_tape_get_state_v4
949 *
950 * This handler handles the ndmp_tape_get_state_request.
951 * Status information for the currently open tape device is returned.
952 *
953 * Parameters:
954 *   connection (input) - connection handle.
955 *   body       (input) - request message body.
956 *
957 * Returns:
958 *   void
959 */
960/*ARGSUSED*/
961void
962ndmpd_tape_get_state_v4(ndmp_connection_t *connection, void *body)
963{
964	ndmp_tape_get_state_reply_v4 reply;
965	ndmpd_session_t *session = ndmp_get_client_data(connection);
966	struct mtget mtstatus;
967	struct mtdrivetype_request dtpr;
968	struct mtdrivetype dtp;
969
970	if (session->ns_tape.td_fd == -1) {
971		NDMP_LOG(LOG_ERR, "Tape device is not open.");
972		reply.error = NDMP_DEV_NOT_OPEN_ERR;
973		ndmp_send_reply(connection, (void *) &reply,
974		    "sending tape_get_state reply");
975		return;
976	}
977
978	/*
979	 * Need code to detect NDMP_TAPE_STATE_NOREWIND
980	 */
981
982	if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
983		NDMP_LOG(LOG_ERR,
984		    "Failed to get status information from tape: %m.");
985		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
986
987		reply.error = NDMP_IO_ERR;
988		ndmp_send_reply(connection, (void *)&reply,
989		    "sending tape_get_state reply");
990		return;
991	}
992
993	dtpr.size = sizeof (struct mtdrivetype);
994	dtpr.mtdtp = &dtp;
995	if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
996		NDMP_LOG(LOG_ERR,
997		    "Failed to get drive type information from tape: %m.");
998		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
999
1000		reply.error = NDMP_IO_ERR;
1001		ndmp_send_reply(connection, (void *)&reply,
1002		    "sending tape_get_state reply");
1003		return;
1004	}
1005
1006	reply.flags = NDMP_TAPE_NOREWIND;
1007
1008	reply.file_num = mtstatus.mt_fileno;
1009	reply.soft_errors = 0;
1010	reply.block_size = dtp.bsize;
1011
1012	if (dtp.bsize == 0)
1013		reply.blockno = mtstatus.mt_blkno;
1014	else
1015		reply.blockno = mtstatus.mt_blkno /
1016		    (session->ns_mover.md_record_size / dtp.bsize);
1017
1018	reply.total_space = long_long_to_quad(0LL); /* not supported */
1019	reply.space_remain = long_long_to_quad(0LL); /* not supported */
1020	reply.soft_errors = 0;
1021	reply.unsupported = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
1022	    NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
1023	    NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
1024	    NDMP_TAPE_STATE_PARTITION_INVALID;
1025
1026	NDMP_LOG(LOG_DEBUG, "f 0x%x, fnum %d, bsize %d, bno: %d",
1027	    reply.flags, reply.file_num, reply.block_size, reply.blockno);
1028
1029	reply.error = NDMP_NO_ERR;
1030	ndmp_send_reply(connection, (void *) &reply,
1031	    "sending tape_get_state reply");
1032}
1033/*
1034 * ndmpd_tape_close_v4
1035 *
1036 * This handler (v4) closes the currently open tape device.
1037 *
1038 * Parameters:
1039 *   connection (input) - connection handle.
1040 *   body       (input) - request message body.
1041 *
1042 * Returns:
1043 *   void
1044 */
1045/*ARGSUSED*/
1046void
1047ndmpd_tape_close_v4(ndmp_connection_t *connection, void *body)
1048{
1049	ndmp_tape_close_reply reply;
1050	ndmpd_session_t *session = ndmp_get_client_data(connection);
1051
1052	if (session->ns_tape.td_fd == -1) {
1053		NDMP_LOG(LOG_ERR, "Tape device is not open.");
1054		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1055		ndmp_send_reply(connection, (void *) &reply,
1056		    "sending tape_close reply");
1057		return;
1058	}
1059
1060	/*
1061	 * V4 suggests that this should not be accepted
1062	 * when mover is in listen or active state
1063	 */
1064	if (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
1065	    session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
1066
1067		reply.error = NDMP_DEVICE_BUSY_ERR;
1068		ndmp_send_reply(connection, (void *) &reply,
1069		    "sending tape_close reply");
1070		return;
1071	}
1072
1073	common_tape_close(connection);
1074}
1075
1076
1077/*
1078 * ************************************************************************
1079 * LOCALS
1080 * ************************************************************************
1081 */
1082/*
1083 * tape_open_send_reply
1084 *
1085 * Send a reply to the tape open message
1086 *
1087 * Parameters:
1088 *   connection (input) - connection handle.
1089 *   err (input) - NDMP error
1090 *
1091 * Returns:
1092 *   void
1093 */
1094static void
1095tape_open_send_reply(ndmp_connection_t *connection, int err)
1096{
1097	ndmp_tape_open_reply reply;
1098
1099	reply.error = err;
1100	ndmp_send_reply(connection, (void *) &reply, "sending tape_open reply");
1101}
1102
1103/*
1104 * unbuffered_read
1105 *
1106 * Perform tape read without read-ahead
1107 *
1108 * Parameters:
1109 *   session (input) - session handle
1110 *   bp (output) - read buffer
1111 *   wanted (input) - number of bytes wanted
1112 *   reply (output) - tape read reply message
1113 *
1114 * Returns:
1115 *   void
1116 */
1117static void
1118unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
1119    ndmp_tape_read_reply *reply)
1120{
1121	int n, len;
1122
1123	n = read(session->ns_tape.td_fd, buf, wanted);
1124	if (n < 0) {
1125		/*
1126		 * This fix is for Symantec during importing
1127		 * of spanned data between the tapes.
1128		 */
1129		if (errno == ENOSPC) {
1130			reply->error = NDMP_EOF_ERR;
1131		} else {
1132			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
1133			reply->error = NDMP_IO_ERR;
1134		}
1135	} else if (n == 0) {
1136		NDMP_LOG(LOG_DEBUG, "NDMP_EOF_ERR");
1137
1138		reply->error = NDMP_EOF_ERR;
1139
1140		(void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
1141
1142		len = strlen(NDMP_EOM_MAGIC);
1143		(void) memset(buf, 0, len);
1144		n = read(session->ns_tape.td_fd, buf, len);
1145		buf[len] = '\0';
1146
1147		NDMP_LOG(LOG_DEBUG, "Checking EOM: nread %d [%s]", n, buf);
1148
1149		(void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
1150
1151		if (strncmp(buf, NDMP_EOM_MAGIC, len) != 0)
1152			(void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
1153	} else {
1154		session->ns_tape.td_pos += n;
1155		reply->data_in.data_in_len = n;
1156		reply->data_in.data_in_val = buf;
1157		reply->error = NDMP_NO_ERR;
1158		NS_ADD(rtape, n);
1159	}
1160}
1161
1162
1163/*
1164 * validmode
1165 *
1166 * Check the tape read mode is valid
1167 */
1168static boolean_t
1169validmode(int mode)
1170{
1171	boolean_t rv;
1172
1173	switch (mode) {
1174	case NDMP_TAPE_READ_MODE:
1175	case NDMP_TAPE_WRITE_MODE:
1176	case NDMP_TAPE_RAW1_MODE:
1177	case NDMP_TAPE_RAW2_MODE:
1178		rv = TRUE;
1179		break;
1180	default:
1181		rv = FALSE;
1182	}
1183
1184	return (rv);
1185}
1186
1187
1188/*
1189 * common_tape_open
1190 *
1191 * Generic function for opening the tape for all versions
1192 *
1193 * Parameters:
1194 *   connection (input) - connection handle.
1195 *   devname (input) - tape device name to open.
1196 *   ndmpmode (input) - mode of opening (read, write, raw)
1197 *
1198 * Returns:
1199 *   void
1200 */
1201static void
1202common_tape_open(ndmp_connection_t *connection, char *devname, int ndmpmode)
1203{
1204	ndmpd_session_t *session = ndmp_get_client_data(connection);
1205	char adptnm[SCSI_MAX_NAME];
1206	int err;
1207	int mode;
1208	int sid, lun;
1209	scsi_adapter_t *sa;
1210	int devid;
1211
1212	err = NDMP_NO_ERR;
1213
1214	if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
1215		NDMP_LOG(LOG_INFO,
1216		    "Connection already has a tape or scsi device open");
1217		err = NDMP_DEVICE_OPENED_ERR;
1218	} else if (!validmode(ndmpmode))
1219		err = NDMP_ILLEGAL_ARGS_ERR;
1220	if ((sa = scsi_get_adapter(0)) != NULL) {
1221		NDMP_LOG(LOG_DEBUG, "Adapter device opened: %s", devname);
1222		(void) strlcpy(adptnm, devname, SCSI_MAX_NAME-2);
1223		adptnm[SCSI_MAX_NAME-1] = '\0';
1224		sid = lun = -1;
1225	}
1226	if (sa) {
1227		scsi_find_sid_lun(sa, devname, &sid, &lun);
1228		if (ndmp_open_list_find(devname, sid, lun) == 0 &&
1229		    (devid = open(devname, O_RDWR | O_NDELAY)) < 0) {
1230			NDMP_LOG(LOG_ERR,
1231			    "Failed to open device %s: %m.", devname);
1232			err = NDMP_NO_DEVICE_ERR;
1233		} else {
1234			(void) close(devid);
1235		}
1236	} else {
1237		NDMP_LOG(LOG_ERR, "%s: No such tape device.", devname);
1238		err = NDMP_NO_DEVICE_ERR;
1239	}
1240
1241	if (err != NDMP_NO_ERR) {
1242		tape_open_send_reply(connection, err);
1243		return;
1244	}
1245
1246	/*
1247	 * If tape is not opened in raw mode and tape is not loaded
1248	 * return error.
1249	 */
1250	if (ndmpmode != NDMP_TAPE_RAW1_MODE &&
1251	    ndmpmode != NDMP_TAPE_RAW2_MODE &&
1252	    !is_tape_unit_ready(adptnm, 0)) {
1253		tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
1254		return;
1255	}
1256
1257	mode = (ndmpmode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
1258	mode |= O_NDELAY;
1259	session->ns_tape.td_fd = open(devname, mode);
1260	if (session->ns_protocol_version == NDMPV4 &&
1261	    session->ns_tape.td_fd < 0 &&
1262	    ndmpmode == NDMP_TAPE_RAW_MODE && errno == EACCES) {
1263		/*
1264		 * V4 suggests that if the tape is open in raw mode
1265		 * and could not be opened with write access, it should
1266		 * be opened read only instead.
1267		 */
1268		ndmpmode = NDMP_TAPE_READ_MODE;
1269		session->ns_tape.td_fd = open(devname, O_RDONLY);
1270	}
1271	if (session->ns_tape.td_fd < 0) {
1272		NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
1273		    devname);
1274		switch (errno) {
1275		case EACCES:
1276			err = NDMP_WRITE_PROTECT_ERR;
1277			break;
1278		case ENOENT:
1279			err = NDMP_NO_DEVICE_ERR;
1280			break;
1281		case EBUSY:
1282			err = NDMP_DEVICE_BUSY_ERR;
1283			break;
1284		case EPERM:
1285			err = NDMP_PERMISSION_ERR;
1286			break;
1287		default:
1288			err = NDMP_IO_ERR;
1289		}
1290
1291		tape_open_send_reply(connection, err);
1292		return;
1293	}
1294
1295	switch (ndmp_open_list_add(connection,
1296	    adptnm, sid, lun, session->ns_tape.td_fd)) {
1297	case 0:
1298		err = NDMP_NO_ERR;
1299		break;
1300	case EBUSY:
1301		err = NDMP_DEVICE_BUSY_ERR;
1302		break;
1303	case ENOMEM:
1304		err = NDMP_NO_MEM_ERR;
1305		break;
1306	default:
1307		err = NDMP_IO_ERR;
1308	}
1309	if (err != NDMP_NO_ERR) {
1310		tape_open_send_reply(connection, err);
1311		return;
1312	}
1313
1314	session->ns_tape.td_mode = ndmpmode;
1315	session->ns_tape.td_sid = sid;
1316	session->ns_tape.td_lun = lun;
1317	(void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
1318	session->ns_tape.td_record_count = 0;
1319
1320	NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
1321
1322	tape_open_send_reply(connection, NDMP_NO_ERR);
1323}
1324
1325
1326/*
1327 * common_tape_close
1328 *
1329 * Generic function for closing the tape
1330 *
1331 * Parameters:
1332 *   connection (input) - connection handle.
1333 *
1334 * Returns:
1335 *   void
1336 */
1337static void
1338common_tape_close(ndmp_connection_t *connection)
1339{
1340	ndmpd_session_t *session = ndmp_get_client_data(connection);
1341	ndmp_tape_close_reply reply;
1342
1343	(void) ndmp_open_list_del(session->ns_tape.td_adapter_name,
1344	    session->ns_tape.td_sid, session->ns_tape.td_lun);
1345	(void) close(session->ns_tape.td_fd);
1346	session->ns_tape.td_fd = -1;
1347	session->ns_tape.td_sid = 0;
1348	session->ns_tape.td_lun = 0;
1349	(void) memset(session->ns_tape.td_adapter_name, 0,
1350	    sizeof (session->ns_tape.td_adapter_name));
1351	session->ns_tape.td_record_count = 0;
1352
1353	reply.error = NDMP_NO_ERR;
1354	ndmp_send_reply(connection, (void *) &reply,
1355	    "sending tape_close reply");
1356}
1357
1358/*
1359 * tape_open
1360 *
1361 * Will try to open the tape with the given flags and
1362 * path using the given retries and delay intervals
1363 */
1364int
1365tape_open(char *path, int flags)
1366{
1367	int fd;
1368	int i = 0;
1369
1370	while ((fd = open(path, flags)) == -1 &&
1371	    i++ < ndmp_tape_open_retries) {
1372		if (errno != EBUSY)
1373			break;
1374		(void) usleep(ndmp_tape_open_delay);
1375	}
1376	return (fd);
1377}
1378