xref: /onnv-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_tape.c (revision 9169:5740ccf44671)
17917SReza.Sabdar@Sun.COM /*
28800SReza.Sabdar@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37917SReza.Sabdar@Sun.COM  * Use is subject to license terms.
47917SReza.Sabdar@Sun.COM  */
57917SReza.Sabdar@Sun.COM 
67917SReza.Sabdar@Sun.COM /*
77917SReza.Sabdar@Sun.COM  * BSD 3 Clause License
87917SReza.Sabdar@Sun.COM  *
97917SReza.Sabdar@Sun.COM  * Copyright (c) 2007, The Storage Networking Industry Association.
107917SReza.Sabdar@Sun.COM  *
117917SReza.Sabdar@Sun.COM  * Redistribution and use in source and binary forms, with or without
127917SReza.Sabdar@Sun.COM  * modification, are permitted provided that the following conditions
137917SReza.Sabdar@Sun.COM  * are met:
147917SReza.Sabdar@Sun.COM  * 	- Redistributions of source code must retain the above copyright
157917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer.
167917SReza.Sabdar@Sun.COM  *
177917SReza.Sabdar@Sun.COM  * 	- Redistributions in binary form must reproduce the above copyright
187917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer in
197917SReza.Sabdar@Sun.COM  *	  the documentation and/or other materials provided with the
207917SReza.Sabdar@Sun.COM  *	  distribution.
217917SReza.Sabdar@Sun.COM  *
227917SReza.Sabdar@Sun.COM  *	- Neither the name of The Storage Networking Industry Association (SNIA)
237917SReza.Sabdar@Sun.COM  *	  nor the names of its contributors may be used to endorse or promote
247917SReza.Sabdar@Sun.COM  *	  products derived from this software without specific prior written
257917SReza.Sabdar@Sun.COM  *	  permission.
267917SReza.Sabdar@Sun.COM  *
277917SReza.Sabdar@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
287917SReza.Sabdar@Sun.COM  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
297917SReza.Sabdar@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
307917SReza.Sabdar@Sun.COM  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
317917SReza.Sabdar@Sun.COM  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
327917SReza.Sabdar@Sun.COM  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
337917SReza.Sabdar@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
347917SReza.Sabdar@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
357917SReza.Sabdar@Sun.COM  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
367917SReza.Sabdar@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
377917SReza.Sabdar@Sun.COM  * POSSIBILITY OF SUCH DAMAGE.
387917SReza.Sabdar@Sun.COM  */
397917SReza.Sabdar@Sun.COM /* Copyright (c) 2007, The Storage Networking Industry Association. */
407917SReza.Sabdar@Sun.COM /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
417917SReza.Sabdar@Sun.COM 
427917SReza.Sabdar@Sun.COM #include <sys/param.h>
437917SReza.Sabdar@Sun.COM #include <fcntl.h>
447917SReza.Sabdar@Sun.COM #include <sys/mtio.h>
457917SReza.Sabdar@Sun.COM #include <errno.h>
467917SReza.Sabdar@Sun.COM #include <stdio.h>
477917SReza.Sabdar@Sun.COM #include <string.h>
487917SReza.Sabdar@Sun.COM #include <unistd.h>
497917SReza.Sabdar@Sun.COM #include "ndmpd_common.h"
507917SReza.Sabdar@Sun.COM #include "ndmpd.h"
517917SReza.Sabdar@Sun.COM 
527917SReza.Sabdar@Sun.COM static void tape_open_send_reply(ndmp_connection_t *connection, int err);
537917SReza.Sabdar@Sun.COM static void unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
547917SReza.Sabdar@Sun.COM     ndmp_tape_read_reply *reply);
557917SReza.Sabdar@Sun.COM static boolean_t validmode(int mode);
567917SReza.Sabdar@Sun.COM static void common_tape_open(ndmp_connection_t *connection, char *devname,
577917SReza.Sabdar@Sun.COM     int ndmpmode);
587917SReza.Sabdar@Sun.COM static void common_tape_close(ndmp_connection_t *connection);
597917SReza.Sabdar@Sun.COM 
607917SReza.Sabdar@Sun.COM /*
617917SReza.Sabdar@Sun.COM  * Configurable delay & time when the tape is
627917SReza.Sabdar@Sun.COM  * busy during opening the tape.
637917SReza.Sabdar@Sun.COM  */
647917SReza.Sabdar@Sun.COM int ndmp_tape_open_retries = 5;
657917SReza.Sabdar@Sun.COM int ndmp_tape_open_delay = 1000;
667917SReza.Sabdar@Sun.COM 
677917SReza.Sabdar@Sun.COM /*
687917SReza.Sabdar@Sun.COM  * ************************************************************************
697917SReza.Sabdar@Sun.COM  * NDMP V2 HANDLERS
707917SReza.Sabdar@Sun.COM  * ************************************************************************
717917SReza.Sabdar@Sun.COM  */
727917SReza.Sabdar@Sun.COM 
737917SReza.Sabdar@Sun.COM /*
747917SReza.Sabdar@Sun.COM  * ndmpd_tape_open_v2
757917SReza.Sabdar@Sun.COM  *
767917SReza.Sabdar@Sun.COM  * This handler opens the specified tape device.
777917SReza.Sabdar@Sun.COM  *
787917SReza.Sabdar@Sun.COM  * Parameters:
797917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
807917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
817917SReza.Sabdar@Sun.COM  *
827917SReza.Sabdar@Sun.COM  * Returns:
837917SReza.Sabdar@Sun.COM  *   void
847917SReza.Sabdar@Sun.COM  */
857917SReza.Sabdar@Sun.COM void
ndmpd_tape_open_v2(ndmp_connection_t * connection,void * body)867917SReza.Sabdar@Sun.COM ndmpd_tape_open_v2(ndmp_connection_t *connection, void *body)
877917SReza.Sabdar@Sun.COM {
887917SReza.Sabdar@Sun.COM 	ndmp_tape_open_request_v2 *request = (ndmp_tape_open_request_v2 *) body;
897917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
907917SReza.Sabdar@Sun.COM 	char adptnm[SCSI_MAX_NAME];
917917SReza.Sabdar@Sun.COM 	int mode;
927917SReza.Sabdar@Sun.COM 	int sid, lun;
937917SReza.Sabdar@Sun.COM 	int err;
947917SReza.Sabdar@Sun.COM 	scsi_adapter_t *sa;
957917SReza.Sabdar@Sun.COM 	int devid;
967917SReza.Sabdar@Sun.COM 
977917SReza.Sabdar@Sun.COM 	err = NDMP_NO_ERR;
987917SReza.Sabdar@Sun.COM 
997917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
1007917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_INFO,
1017917SReza.Sabdar@Sun.COM 		    "Connection already has a tape or scsi device open");
1027917SReza.Sabdar@Sun.COM 		err = NDMP_DEVICE_OPENED_ERR;
1037917SReza.Sabdar@Sun.COM 	} else if (request->mode != NDMP_TAPE_READ_MODE &&
1047917SReza.Sabdar@Sun.COM 	    request->mode != NDMP_TAPE_WRITE_MODE &&
1057917SReza.Sabdar@Sun.COM 	    request->mode != NDMP_TAPE_RAW1_MODE) {
1067917SReza.Sabdar@Sun.COM 		err = NDMP_ILLEGAL_ARGS_ERR;
1077917SReza.Sabdar@Sun.COM 	}
1087917SReza.Sabdar@Sun.COM 
1097917SReza.Sabdar@Sun.COM 	if ((sa = scsi_get_adapter(0)) != NULL) {
1107917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
1117917SReza.Sabdar@Sun.COM 		    "Adapter device opened: %s", request->device.name);
1127917SReza.Sabdar@Sun.COM 		(void) strlcpy(adptnm, request->device.name, SCSI_MAX_NAME-2);
1137917SReza.Sabdar@Sun.COM 		adptnm[SCSI_MAX_NAME-1] = '\0';
1147917SReza.Sabdar@Sun.COM 		sid = lun = -1;
1157917SReza.Sabdar@Sun.COM 	}
1167917SReza.Sabdar@Sun.COM 	/* try to get the scsi id etc.... */
1177917SReza.Sabdar@Sun.COM 	if (sa) {
1187917SReza.Sabdar@Sun.COM 		scsi_find_sid_lun(sa, request->device.name, &sid, &lun);
1197917SReza.Sabdar@Sun.COM 		if (ndmp_open_list_find(request->device.name, sid, lun) == 0 &&
1207917SReza.Sabdar@Sun.COM 		    (devid = tape_open(request->device.name,
1217917SReza.Sabdar@Sun.COM 		    O_RDWR | O_NDELAY)) < 0) {
1227917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Failed to open device %s: %m.",
1237917SReza.Sabdar@Sun.COM 			    request->device.name);
1247917SReza.Sabdar@Sun.COM 			err = NDMP_NO_DEVICE_ERR;
1257917SReza.Sabdar@Sun.COM 		}
1267917SReza.Sabdar@Sun.COM 		else
1277917SReza.Sabdar@Sun.COM 			(void) close(devid);
1287917SReza.Sabdar@Sun.COM 	} else {
1297917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "%s: No such tape device.",
1307917SReza.Sabdar@Sun.COM 		    request->device.name);
1317917SReza.Sabdar@Sun.COM 		err = NDMP_NO_DEVICE_ERR;
1327917SReza.Sabdar@Sun.COM 	}
1337917SReza.Sabdar@Sun.COM 	if (err != NDMP_NO_ERR) {
1347917SReza.Sabdar@Sun.COM 		tape_open_send_reply(connection, err);
1357917SReza.Sabdar@Sun.COM 		return;
1367917SReza.Sabdar@Sun.COM 	}
1377917SReza.Sabdar@Sun.COM 
1387917SReza.Sabdar@Sun.COM 	switch (ndmp_open_list_add(connection, adptnm, sid, lun, devid)) {
1397917SReza.Sabdar@Sun.COM 	case 0:
1407917SReza.Sabdar@Sun.COM 		err = NDMP_NO_ERR;
1417917SReza.Sabdar@Sun.COM 		break;
1427917SReza.Sabdar@Sun.COM 	case EBUSY:
1437917SReza.Sabdar@Sun.COM 		err = NDMP_DEVICE_BUSY_ERR;
1447917SReza.Sabdar@Sun.COM 		break;
1457917SReza.Sabdar@Sun.COM 	case ENOMEM:
1467917SReza.Sabdar@Sun.COM 		err = NDMP_NO_MEM_ERR;
1477917SReza.Sabdar@Sun.COM 		break;
1487917SReza.Sabdar@Sun.COM 	default:
1497917SReza.Sabdar@Sun.COM 		err = NDMP_IO_ERR;
1507917SReza.Sabdar@Sun.COM 	}
1517917SReza.Sabdar@Sun.COM 	if (err != NDMP_NO_ERR) {
1527917SReza.Sabdar@Sun.COM 		tape_open_send_reply(connection, err);
1537917SReza.Sabdar@Sun.COM 		return;
1547917SReza.Sabdar@Sun.COM 	}
1557917SReza.Sabdar@Sun.COM 
1567917SReza.Sabdar@Sun.COM 	/*
1577917SReza.Sabdar@Sun.COM 	 * According to Connectathon 2001, the 0x7fffffff is a secret
1587917SReza.Sabdar@Sun.COM 	 * code between "Workstartion Solutions" and * net_app.
1597917SReza.Sabdar@Sun.COM 	 * If mode is set to this value, tape_open() won't fail if
1607917SReza.Sabdar@Sun.COM 	 * the tape device is not ready.
1617917SReza.Sabdar@Sun.COM 	 */
1627917SReza.Sabdar@Sun.COM 	if (request->mode != NDMP_TAPE_RAW1_MODE &&
1637917SReza.Sabdar@Sun.COM 	    !is_tape_unit_ready(adptnm, 0)) {
1647917SReza.Sabdar@Sun.COM 		(void) ndmp_open_list_del(adptnm, sid, lun);
1657917SReza.Sabdar@Sun.COM 		tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
1667917SReza.Sabdar@Sun.COM 		return;
1677917SReza.Sabdar@Sun.COM 	}
1687917SReza.Sabdar@Sun.COM 
1697917SReza.Sabdar@Sun.COM 	mode = (request->mode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
1707917SReza.Sabdar@Sun.COM 	mode |= O_NDELAY;
1717917SReza.Sabdar@Sun.COM 	if ((session->ns_tape.td_fd = open(request->device.name, mode)) < 0) {
1727917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
1737917SReza.Sabdar@Sun.COM 			    request->device.name);
1747917SReza.Sabdar@Sun.COM 			switch (errno) {
1757917SReza.Sabdar@Sun.COM 			case EACCES:
1767917SReza.Sabdar@Sun.COM 				err = NDMP_WRITE_PROTECT_ERR;
1777917SReza.Sabdar@Sun.COM 				break;
1787917SReza.Sabdar@Sun.COM 			case ENXIO:
1797917SReza.Sabdar@Sun.COM 			case ENOENT:
1807917SReza.Sabdar@Sun.COM 				err = NDMP_NO_DEVICE_ERR;
1817917SReza.Sabdar@Sun.COM 				break;
1827917SReza.Sabdar@Sun.COM 			case EBUSY:
1837917SReza.Sabdar@Sun.COM 				err = NDMP_DEVICE_BUSY_ERR;
1847917SReza.Sabdar@Sun.COM 				break;
1857917SReza.Sabdar@Sun.COM 			default:
1867917SReza.Sabdar@Sun.COM 				err = NDMP_IO_ERR;
1877917SReza.Sabdar@Sun.COM 			}
1887917SReza.Sabdar@Sun.COM 
1897917SReza.Sabdar@Sun.COM 			(void) ndmp_open_list_del(adptnm, sid, lun);
1907917SReza.Sabdar@Sun.COM 			tape_open_send_reply(connection, err);
1917917SReza.Sabdar@Sun.COM 			return;
1927917SReza.Sabdar@Sun.COM 		}
1937917SReza.Sabdar@Sun.COM 
1947917SReza.Sabdar@Sun.COM 	session->ns_tape.td_mode = request->mode;
1957917SReza.Sabdar@Sun.COM 	session->ns_tape.td_sid = sid;
1967917SReza.Sabdar@Sun.COM 	session->ns_tape.td_lun = lun;
1977917SReza.Sabdar@Sun.COM 	(void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
1987917SReza.Sabdar@Sun.COM 	session->ns_tape.td_record_count = 0;
1997917SReza.Sabdar@Sun.COM 	session->ns_tape.td_eom_seen = FALSE;
2007917SReza.Sabdar@Sun.COM 
2017917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
2027917SReza.Sabdar@Sun.COM 
2037917SReza.Sabdar@Sun.COM 	tape_open_send_reply(connection, NDMP_NO_ERR);
2047917SReza.Sabdar@Sun.COM }
2057917SReza.Sabdar@Sun.COM 
2067917SReza.Sabdar@Sun.COM 
2077917SReza.Sabdar@Sun.COM /*
2087917SReza.Sabdar@Sun.COM  * ndmpd_tape_close_v2
2097917SReza.Sabdar@Sun.COM  *
2107917SReza.Sabdar@Sun.COM  * This handler closes the currently open tape device.
2117917SReza.Sabdar@Sun.COM  *
2127917SReza.Sabdar@Sun.COM  * Parameters:
2137917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
2147917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
2157917SReza.Sabdar@Sun.COM  *
2167917SReza.Sabdar@Sun.COM  * Returns:
2177917SReza.Sabdar@Sun.COM  *   void
2187917SReza.Sabdar@Sun.COM  */
2197917SReza.Sabdar@Sun.COM /*ARGSUSED*/
2207917SReza.Sabdar@Sun.COM void
ndmpd_tape_close_v2(ndmp_connection_t * connection,void * body)2217917SReza.Sabdar@Sun.COM ndmpd_tape_close_v2(ndmp_connection_t *connection, void *body)
2227917SReza.Sabdar@Sun.COM {
2237917SReza.Sabdar@Sun.COM 	ndmp_tape_close_reply reply;
2247917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
2257917SReza.Sabdar@Sun.COM 
2267917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
2277917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
2287917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
2297917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
2307917SReza.Sabdar@Sun.COM 		    "sending tape_close reply");
2317917SReza.Sabdar@Sun.COM 		return;
2327917SReza.Sabdar@Sun.COM 	}
2337917SReza.Sabdar@Sun.COM 	common_tape_close(connection);
2347917SReza.Sabdar@Sun.COM 
2357917SReza.Sabdar@Sun.COM }
2367917SReza.Sabdar@Sun.COM 
2377917SReza.Sabdar@Sun.COM /*
2387917SReza.Sabdar@Sun.COM  * ndmpd_tape_get_state_v2
2397917SReza.Sabdar@Sun.COM  *
2407917SReza.Sabdar@Sun.COM  * This handler handles the tape_get_state request.
2417917SReza.Sabdar@Sun.COM  * Status information for the currently open tape device is returned.
2427917SReza.Sabdar@Sun.COM  *
2437917SReza.Sabdar@Sun.COM  * Parameters:
2447917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
2457917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
2467917SReza.Sabdar@Sun.COM  *
2477917SReza.Sabdar@Sun.COM  * Returns:
2487917SReza.Sabdar@Sun.COM  *   void
2497917SReza.Sabdar@Sun.COM  */
2507917SReza.Sabdar@Sun.COM /*ARGSUSED*/
2517917SReza.Sabdar@Sun.COM void
ndmpd_tape_get_state_v2(ndmp_connection_t * connection,void * body)2527917SReza.Sabdar@Sun.COM ndmpd_tape_get_state_v2(ndmp_connection_t *connection, void *body)
2537917SReza.Sabdar@Sun.COM 
2547917SReza.Sabdar@Sun.COM {
2557917SReza.Sabdar@Sun.COM 	ndmp_tape_get_state_reply_v2 reply;
2567917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
2577917SReza.Sabdar@Sun.COM 	struct mtget mtstatus;
2587917SReza.Sabdar@Sun.COM 	struct mtdrivetype_request dtpr;
2597917SReza.Sabdar@Sun.COM 	struct mtdrivetype dtp;
2607917SReza.Sabdar@Sun.COM 
2617917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
2627917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
2637917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
2647917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
2657917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
2667917SReza.Sabdar@Sun.COM 		return;
2677917SReza.Sabdar@Sun.COM 	}
2687917SReza.Sabdar@Sun.COM 
2697917SReza.Sabdar@Sun.COM 	if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) < 0) {
2707917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Failed to get status from tape: %m.");
2717917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
2727917SReza.Sabdar@Sun.COM 		reply.error = NDMP_IO_ERR;
2737917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
2747917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
2757917SReza.Sabdar@Sun.COM 		return;
2767917SReza.Sabdar@Sun.COM 	}
2777917SReza.Sabdar@Sun.COM 
2787917SReza.Sabdar@Sun.COM 	dtpr.size = sizeof (struct mtdrivetype);
2797917SReza.Sabdar@Sun.COM 	dtpr.mtdtp = &dtp;
2807917SReza.Sabdar@Sun.COM 	if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
2817917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR,
2827917SReza.Sabdar@Sun.COM 		    "Failed to get drive type information from tape: %m.");
2837917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
2847917SReza.Sabdar@Sun.COM 		reply.error = NDMP_IO_ERR;
2857917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
2867917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
2877917SReza.Sabdar@Sun.COM 		return;
2887917SReza.Sabdar@Sun.COM 	}
2897917SReza.Sabdar@Sun.COM 
2907917SReza.Sabdar@Sun.COM 	reply.flags = 0;
2917917SReza.Sabdar@Sun.COM 
2927917SReza.Sabdar@Sun.COM 	reply.file_num = mtstatus.mt_fileno;
2937917SReza.Sabdar@Sun.COM 	reply.soft_errors = 0;
2947917SReza.Sabdar@Sun.COM 	reply.block_size = dtp.bsize;
2957917SReza.Sabdar@Sun.COM 	if (dtp.bsize == 0)
2967917SReza.Sabdar@Sun.COM 		reply.blockno = mtstatus.mt_blkno;
2977917SReza.Sabdar@Sun.COM 	else
2987917SReza.Sabdar@Sun.COM 		reply.blockno = mtstatus.mt_blkno *
2997917SReza.Sabdar@Sun.COM 		    (session->ns_mover.md_record_size / dtp.bsize);
3007917SReza.Sabdar@Sun.COM 
3017917SReza.Sabdar@Sun.COM 	reply.soft_errors = 0;
3027917SReza.Sabdar@Sun.COM 	reply.total_space = long_long_to_quad(0);	/* not supported */
3037917SReza.Sabdar@Sun.COM 	reply.space_remain = long_long_to_quad(0);	/* not supported */
3047917SReza.Sabdar@Sun.COM 
3057917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG,
3067917SReza.Sabdar@Sun.COM 	    "flags: 0x%x, file_num: %d, block_size: %d, blockno: %d",
3077917SReza.Sabdar@Sun.COM 	    reply.flags, reply.file_num, reply.block_size, reply.blockno);
3087917SReza.Sabdar@Sun.COM 
3097917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
3107917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
3117917SReza.Sabdar@Sun.COM 	    "sending tape_get_state reply");
3127917SReza.Sabdar@Sun.COM }
3137917SReza.Sabdar@Sun.COM 
3147917SReza.Sabdar@Sun.COM 
3157917SReza.Sabdar@Sun.COM /*
3167917SReza.Sabdar@Sun.COM  * ndmpd_tape_mtio_v2
3177917SReza.Sabdar@Sun.COM  *
3187917SReza.Sabdar@Sun.COM  * This handler handles tape_mtio requests.
3197917SReza.Sabdar@Sun.COM  *
3207917SReza.Sabdar@Sun.COM  * Parameters:
3217917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
3227917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
3237917SReza.Sabdar@Sun.COM  *
3247917SReza.Sabdar@Sun.COM  * Returns:
3257917SReza.Sabdar@Sun.COM  *   void
3267917SReza.Sabdar@Sun.COM  */
3277917SReza.Sabdar@Sun.COM void
ndmpd_tape_mtio_v2(ndmp_connection_t * connection,void * body)3287917SReza.Sabdar@Sun.COM ndmpd_tape_mtio_v2(ndmp_connection_t *connection, void *body)
3297917SReza.Sabdar@Sun.COM {
3307917SReza.Sabdar@Sun.COM 	ndmp_tape_mtio_request *request = (ndmp_tape_mtio_request *) body;
3317917SReza.Sabdar@Sun.COM 	ndmp_tape_mtio_reply reply;
3327917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
3337917SReza.Sabdar@Sun.COM 
3347917SReza.Sabdar@Sun.COM 	struct mtop tapeop;
3357917SReza.Sabdar@Sun.COM 	struct mtget mtstatus;
3367917SReza.Sabdar@Sun.COM 	int retry = 0;
3377917SReza.Sabdar@Sun.COM 	int rc;
3387917SReza.Sabdar@Sun.COM 
3397917SReza.Sabdar@Sun.COM 	reply.resid_count = 0;
3407917SReza.Sabdar@Sun.COM 
3417917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
3427917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
3437917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
3447917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
3457917SReza.Sabdar@Sun.COM 		    "sending tape_mtio reply");
3467917SReza.Sabdar@Sun.COM 		return;
3477917SReza.Sabdar@Sun.COM 	}
3487917SReza.Sabdar@Sun.COM 
3497917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
3507917SReza.Sabdar@Sun.COM 	switch (request->tape_op) {
3517917SReza.Sabdar@Sun.COM 	case NDMP_MTIO_FSF:
3527917SReza.Sabdar@Sun.COM 		tapeop.mt_op = MTFSF;
3537917SReza.Sabdar@Sun.COM 		break;
3547917SReza.Sabdar@Sun.COM 	case NDMP_MTIO_BSF:
3557917SReza.Sabdar@Sun.COM 		tapeop.mt_op = MTBSF;
3567917SReza.Sabdar@Sun.COM 		break;
3577917SReza.Sabdar@Sun.COM 	case NDMP_MTIO_FSR:
3587917SReza.Sabdar@Sun.COM 		tapeop.mt_op = MTFSR;
3597917SReza.Sabdar@Sun.COM 		break;
3607917SReza.Sabdar@Sun.COM 	case NDMP_MTIO_BSR:
3617917SReza.Sabdar@Sun.COM 		tapeop.mt_op = MTBSR;
3627917SReza.Sabdar@Sun.COM 		break;
3637917SReza.Sabdar@Sun.COM 	case NDMP_MTIO_REW:
3647917SReza.Sabdar@Sun.COM 		tapeop.mt_op = MTREW;
3657917SReza.Sabdar@Sun.COM 		break;
3667917SReza.Sabdar@Sun.COM 	case NDMP_MTIO_EOF:
3677917SReza.Sabdar@Sun.COM 		if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE)
3687917SReza.Sabdar@Sun.COM 			reply.error = NDMP_PERMISSION_ERR;
3697917SReza.Sabdar@Sun.COM 		tapeop.mt_op = MTWEOF;
3707917SReza.Sabdar@Sun.COM 		break;
3717917SReza.Sabdar@Sun.COM 	case NDMP_MTIO_OFF:
3727917SReza.Sabdar@Sun.COM 		tapeop.mt_op = MTOFFL;
3737917SReza.Sabdar@Sun.COM 		break;
3747917SReza.Sabdar@Sun.COM 
3757917SReza.Sabdar@Sun.COM 	case NDMP_MTIO_TUR: /* test unit ready */
3767917SReza.Sabdar@Sun.COM 
3777917SReza.Sabdar@Sun.COM 		if (is_tape_unit_ready(session->ns_tape.td_adapter_name,
3787917SReza.Sabdar@Sun.COM 		    session->ns_tape.td_fd) == 0)
3797917SReza.Sabdar@Sun.COM 			/* tape not ready ? */
3807917SReza.Sabdar@Sun.COM 			reply.error = NDMP_NO_TAPE_LOADED_ERR;
3817917SReza.Sabdar@Sun.COM 		break;
3827917SReza.Sabdar@Sun.COM 
3837917SReza.Sabdar@Sun.COM 	default:
3847917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
3857917SReza.Sabdar@Sun.COM 	}
3867917SReza.Sabdar@Sun.COM 
3877917SReza.Sabdar@Sun.COM 	if (reply.error == NDMP_NO_ERR && request->tape_op != NDMP_MTIO_TUR) {
3887917SReza.Sabdar@Sun.COM 		tapeop.mt_count = request->count;
3897917SReza.Sabdar@Sun.COM 
3907917SReza.Sabdar@Sun.COM 		do {
3917917SReza.Sabdar@Sun.COM 			NS_UPD(twait, trun);
3927917SReza.Sabdar@Sun.COM 			rc = ioctl(session->ns_tape.td_fd, MTIOCTOP, &tapeop);
3937917SReza.Sabdar@Sun.COM 			NS_UPD(trun, twait);
3947917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
3957917SReza.Sabdar@Sun.COM 			    "ioctl MTIO rc:%d, cmd:%d, retry:%d, error: %d",
3967917SReza.Sabdar@Sun.COM 			    rc, tapeop.mt_op, retry, errno);
3977917SReza.Sabdar@Sun.COM 		} while (rc < 0 && errno == EIO &&
3987917SReza.Sabdar@Sun.COM 		    retry++ < 5);
3997917SReza.Sabdar@Sun.COM 
4007917SReza.Sabdar@Sun.COM 		/*
4017917SReza.Sabdar@Sun.COM 		 * Ignore I/O errors since these usually are the result of
4027917SReza.Sabdar@Sun.COM 		 * attempting to position past the beginning or end of the tape.
4037917SReza.Sabdar@Sun.COM 		 * The residual count will be returned and can be used to
4047917SReza.Sabdar@Sun.COM 		 * determine that the call was not completely successful.
4057917SReza.Sabdar@Sun.COM 		 */
4067917SReza.Sabdar@Sun.COM 		if (rc < 0) {
4077917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR,
4087917SReza.Sabdar@Sun.COM 			    "Failed to send command to tape: %m.");
4097917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCTOP) error: %m.");
4107917SReza.Sabdar@Sun.COM 
4117917SReza.Sabdar@Sun.COM 			/* MTWEOF doesnt have residual count */
4127917SReza.Sabdar@Sun.COM 			if (tapeop.mt_op == MTWEOF)
4137917SReza.Sabdar@Sun.COM 				reply.error = NDMP_IO_ERR;
4147917SReza.Sabdar@Sun.COM 			else
4157917SReza.Sabdar@Sun.COM 				reply.error = NDMP_NO_ERR;
4167917SReza.Sabdar@Sun.COM 			reply.resid_count = tapeop.mt_count;
4177917SReza.Sabdar@Sun.COM 			ndmp_send_reply(connection, (void *)&reply,
4187917SReza.Sabdar@Sun.COM 			    "sending tape_mtio reply");
4197917SReza.Sabdar@Sun.COM 			return;
4207917SReza.Sabdar@Sun.COM 		}
4217917SReza.Sabdar@Sun.COM 
4227917SReza.Sabdar@Sun.COM 		if (request->tape_op != NDMP_MTIO_REW &&
4237917SReza.Sabdar@Sun.COM 		    request->tape_op != NDMP_MTIO_OFF) {
4247917SReza.Sabdar@Sun.COM 			if (ioctl(session->ns_tape.td_fd, MTIOCGET,
4257917SReza.Sabdar@Sun.COM 			    &mtstatus) < 0) {
4267917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_ERR,
4277917SReza.Sabdar@Sun.COM 				    "Failed to send command to tape: %m.");
4287917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
4297917SReza.Sabdar@Sun.COM 				    "ioctl(MTIOCGET) error: %m.");
4307917SReza.Sabdar@Sun.COM 				reply.error = NDMP_IO_ERR;
4317917SReza.Sabdar@Sun.COM 				ndmp_send_reply(connection, (void *)&reply,
4327917SReza.Sabdar@Sun.COM 				    "sending tape_mtio reply");
4337917SReza.Sabdar@Sun.COM 
4347917SReza.Sabdar@Sun.COM 				return;
4357917SReza.Sabdar@Sun.COM 			}
4367917SReza.Sabdar@Sun.COM 
4377917SReza.Sabdar@Sun.COM 			reply.resid_count = labs(mtstatus.mt_resid);
4387917SReza.Sabdar@Sun.COM 		}
4397917SReza.Sabdar@Sun.COM 	}
4407917SReza.Sabdar@Sun.COM 
4417917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "resid_count: %d",
4427917SReza.Sabdar@Sun.COM 	    reply.resid_count);
4437917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply, "sending tape_mtio reply");
4447917SReza.Sabdar@Sun.COM }
4457917SReza.Sabdar@Sun.COM 
4467917SReza.Sabdar@Sun.COM 
4477917SReza.Sabdar@Sun.COM /*
4487917SReza.Sabdar@Sun.COM  * ndmpd_tape_write_v2
4497917SReza.Sabdar@Sun.COM  *
4507917SReza.Sabdar@Sun.COM  * This handler handles tape_write requests.
4517917SReza.Sabdar@Sun.COM  * This interface is a non-buffered interface. Each write request
4527917SReza.Sabdar@Sun.COM  * maps directly to a write to the tape device. It is the responsibility
4537917SReza.Sabdar@Sun.COM  * of the NDMP client to pad the data to the desired record size.
4547917SReza.Sabdar@Sun.COM  * It is the responsibility of the NDMP client to ensure that the
4557917SReza.Sabdar@Sun.COM  * length is a multiple of the tape block size if the tape device
4567917SReza.Sabdar@Sun.COM  * is in fixed block mode.
4577917SReza.Sabdar@Sun.COM  *
4587917SReza.Sabdar@Sun.COM  * Parameters:
4597917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
4607917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
4617917SReza.Sabdar@Sun.COM  *
4627917SReza.Sabdar@Sun.COM  * Returns:
4637917SReza.Sabdar@Sun.COM  *   void
4647917SReza.Sabdar@Sun.COM  */
4657917SReza.Sabdar@Sun.COM void
ndmpd_tape_write_v2(ndmp_connection_t * connection,void * body)4667917SReza.Sabdar@Sun.COM ndmpd_tape_write_v2(ndmp_connection_t *connection, void *body)
4677917SReza.Sabdar@Sun.COM {
4687917SReza.Sabdar@Sun.COM 	ndmp_tape_write_request *request = (ndmp_tape_write_request *) body;
4697917SReza.Sabdar@Sun.COM 	ndmp_tape_write_reply reply;
4707917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
4717917SReza.Sabdar@Sun.COM 	ssize_t n;
4727917SReza.Sabdar@Sun.COM 
4737917SReza.Sabdar@Sun.COM 	reply.count = 0;
4747917SReza.Sabdar@Sun.COM 
4757917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
4767917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
4777917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
4787917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
4797917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
4807917SReza.Sabdar@Sun.COM 		return;
4817917SReza.Sabdar@Sun.COM 	}
4827917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
4837917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_INFO, "Tape device opened in read-only mode");
4847917SReza.Sabdar@Sun.COM 		reply.error = NDMP_PERMISSION_ERR;
4857917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
4867917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
4877917SReza.Sabdar@Sun.COM 		return;
4887917SReza.Sabdar@Sun.COM 	}
4897917SReza.Sabdar@Sun.COM 	if (request->data_out.data_out_len == 0) {
4907917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
4917917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
4927917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
4937917SReza.Sabdar@Sun.COM 		return;
4947917SReza.Sabdar@Sun.COM 	}
4957917SReza.Sabdar@Sun.COM 
4967917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_eom_seen) {
4977917SReza.Sabdar@Sun.COM 		/*
4987917SReza.Sabdar@Sun.COM 		 * Refer to the comment at the top of this file for
4997917SReza.Sabdar@Sun.COM 		 * Mammoth2 tape drives.
5007917SReza.Sabdar@Sun.COM 		 */
5017917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "eom_seen");
5027917SReza.Sabdar@Sun.COM 		ndmpd_write_eom(session->ns_tape.td_fd);
5037917SReza.Sabdar@Sun.COM 
5047917SReza.Sabdar@Sun.COM 		session->ns_tape.td_eom_seen = FALSE;
5057917SReza.Sabdar@Sun.COM 		reply.error = NDMP_EOM_ERR;
5067917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
5077917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
5087917SReza.Sabdar@Sun.COM 		return;
5097917SReza.Sabdar@Sun.COM 	}
5107917SReza.Sabdar@Sun.COM 
5117917SReza.Sabdar@Sun.COM 	n = write(session->ns_tape.td_fd, request->data_out.data_out_val,
5127917SReza.Sabdar@Sun.COM 	    request->data_out.data_out_len);
5137917SReza.Sabdar@Sun.COM 	if (n >= 0) {
5147917SReza.Sabdar@Sun.COM 		session->ns_tape.td_write = 1;
5157917SReza.Sabdar@Sun.COM 		NS_ADD(wtape, n);
5167917SReza.Sabdar@Sun.COM 	}
5177917SReza.Sabdar@Sun.COM 	if (n == 0) {
5187917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "n == 0");
5197917SReza.Sabdar@Sun.COM 		reply.error = NDMP_EOM_ERR;
5207917SReza.Sabdar@Sun.COM 		session->ns_tape.td_eom_seen = FALSE;
5217917SReza.Sabdar@Sun.COM 	} else if (n < 0) {
5227917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
5237917SReza.Sabdar@Sun.COM 		reply.error = NDMP_IO_ERR;
5247917SReza.Sabdar@Sun.COM 	} else {
5257917SReza.Sabdar@Sun.COM 		reply.count = n;
5267917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
5277917SReza.Sabdar@Sun.COM 
5287917SReza.Sabdar@Sun.COM 		/*
5297917SReza.Sabdar@Sun.COM 		 * a logical end of tape will return number of bytes written
5307917SReza.Sabdar@Sun.COM 		 * less than rquested, and one more request to write will
5317917SReza.Sabdar@Sun.COM 		 * give 0, and then no-space
5327917SReza.Sabdar@Sun.COM 		 */
5337917SReza.Sabdar@Sun.COM 		if (n < request->data_out.data_out_len) {
5347917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "LEOT: n: %d", n);
5357917SReza.Sabdar@Sun.COM 			session->ns_tape.td_eom_seen = TRUE;
5367917SReza.Sabdar@Sun.COM 		} else {
5377917SReza.Sabdar@Sun.COM 			session->ns_tape.td_eom_seen = FALSE;
5387917SReza.Sabdar@Sun.COM 		}
5397917SReza.Sabdar@Sun.COM 	}
5407917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, &reply,
5417917SReza.Sabdar@Sun.COM 	    "sending tape_write reply");
5427917SReza.Sabdar@Sun.COM }
5437917SReza.Sabdar@Sun.COM 
5447917SReza.Sabdar@Sun.COM 
5457917SReza.Sabdar@Sun.COM /*
5467917SReza.Sabdar@Sun.COM  * ndmpd_tape_read_v2
5477917SReza.Sabdar@Sun.COM  *
5487917SReza.Sabdar@Sun.COM  * This handler handles tape_read requests.
5497917SReza.Sabdar@Sun.COM  * This interface is a non-buffered interface. Each read request
5507917SReza.Sabdar@Sun.COM  * maps directly to a read to the tape device. It is the responsibility
5517917SReza.Sabdar@Sun.COM  * of the NDMP client to issue read requests with a length that is at
5527917SReza.Sabdar@Sun.COM  * least as large as the record size used write the tape. The tape driver
5537917SReza.Sabdar@Sun.COM  * always reads a full record. Data is discarded if the read request is
5547917SReza.Sabdar@Sun.COM  * smaller than the record size.
5557917SReza.Sabdar@Sun.COM  * It is the responsibility of the NDMP client to ensure that the
5567917SReza.Sabdar@Sun.COM  * length is a multiple of the tape block size if the tape device
5577917SReza.Sabdar@Sun.COM  * is in fixed block mode.
5587917SReza.Sabdar@Sun.COM  *
5597917SReza.Sabdar@Sun.COM  * Parameters:
5607917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
5617917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
5627917SReza.Sabdar@Sun.COM  *
5637917SReza.Sabdar@Sun.COM  * Returns:
5647917SReza.Sabdar@Sun.COM  *   void
5657917SReza.Sabdar@Sun.COM  */
5667917SReza.Sabdar@Sun.COM void
ndmpd_tape_read_v2(ndmp_connection_t * connection,void * body)5677917SReza.Sabdar@Sun.COM ndmpd_tape_read_v2(ndmp_connection_t *connection, void *body)
5687917SReza.Sabdar@Sun.COM {
5697917SReza.Sabdar@Sun.COM 	ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
5707917SReza.Sabdar@Sun.COM 	ndmp_tape_read_reply reply;
5717917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
5727917SReza.Sabdar@Sun.COM 	char *buf;
5737917SReza.Sabdar@Sun.COM 
5747917SReza.Sabdar@Sun.COM 	reply.data_in.data_in_len = 0;
5757917SReza.Sabdar@Sun.COM 
5767917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
5777917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
5787917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
5797917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
5807917SReza.Sabdar@Sun.COM 		    "sending tape_read reply");
5817917SReza.Sabdar@Sun.COM 		return;
5827917SReza.Sabdar@Sun.COM 	}
5837917SReza.Sabdar@Sun.COM 	if (request->count == 0) {
5847917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
5857917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
5867917SReza.Sabdar@Sun.COM 		    "sending tape_read reply");
5877917SReza.Sabdar@Sun.COM 		return;
5887917SReza.Sabdar@Sun.COM 	}
5897917SReza.Sabdar@Sun.COM 	if ((buf = ndmp_malloc(request->count)) == 0) {
5907917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_MEM_ERR;
5917917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
5927917SReza.Sabdar@Sun.COM 		    "sending tape_read reply");
5937917SReza.Sabdar@Sun.COM 		return;
5947917SReza.Sabdar@Sun.COM 	}
5957917SReza.Sabdar@Sun.COM 
5967917SReza.Sabdar@Sun.COM 	session->ns_tape.td_eom_seen = FALSE;
5977917SReza.Sabdar@Sun.COM 
5987917SReza.Sabdar@Sun.COM 	unbuffered_read(session, buf, request->count, &reply);
5997917SReza.Sabdar@Sun.COM 
6007917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
6017917SReza.Sabdar@Sun.COM 	(void) free(buf);
6027917SReza.Sabdar@Sun.COM }
6037917SReza.Sabdar@Sun.COM 
6047917SReza.Sabdar@Sun.COM 
6057917SReza.Sabdar@Sun.COM /*
6067917SReza.Sabdar@Sun.COM  * ndmpd_tape_execute_cdb_v2
6077917SReza.Sabdar@Sun.COM  *
6087917SReza.Sabdar@Sun.COM  * This handler handles tape_execute_cdb requests.
6097917SReza.Sabdar@Sun.COM  *
6107917SReza.Sabdar@Sun.COM  * Parameters:
6117917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
6127917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
6137917SReza.Sabdar@Sun.COM  *
6147917SReza.Sabdar@Sun.COM  * Returns:
6157917SReza.Sabdar@Sun.COM  *   void
6167917SReza.Sabdar@Sun.COM  */
6177917SReza.Sabdar@Sun.COM void
ndmpd_tape_execute_cdb_v2(ndmp_connection_t * connection,void * body)6187917SReza.Sabdar@Sun.COM ndmpd_tape_execute_cdb_v2(ndmp_connection_t *connection, void *body)
6197917SReza.Sabdar@Sun.COM {
6207917SReza.Sabdar@Sun.COM 	ndmp_tape_execute_cdb_request *request;
6217917SReza.Sabdar@Sun.COM 	ndmp_tape_execute_cdb_reply reply;
6227917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
6237917SReza.Sabdar@Sun.COM 
6247917SReza.Sabdar@Sun.COM 	request = (ndmp_tape_execute_cdb_request *) body;
6257917SReza.Sabdar@Sun.COM 
6267917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
6277917SReza.Sabdar@Sun.COM 		(void) memset((void *) &reply, 0, sizeof (reply));
6287917SReza.Sabdar@Sun.COM 
6297917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
6307917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
6317917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
6327917SReza.Sabdar@Sun.COM 		    "sending tape_execute_cdb reply");
6337917SReza.Sabdar@Sun.COM 	} else {
6347917SReza.Sabdar@Sun.COM 		session->ns_tape.td_eom_seen = FALSE;
6357917SReza.Sabdar@Sun.COM 		ndmp_execute_cdb(session, session->ns_tape.td_adapter_name,
6367917SReza.Sabdar@Sun.COM 		    session->ns_tape.td_sid, session->ns_tape.td_lun,
6377917SReza.Sabdar@Sun.COM 		    (ndmp_execute_cdb_request *)request);
6387917SReza.Sabdar@Sun.COM 	}
6397917SReza.Sabdar@Sun.COM }
6407917SReza.Sabdar@Sun.COM 
6417917SReza.Sabdar@Sun.COM 
6427917SReza.Sabdar@Sun.COM /*
6437917SReza.Sabdar@Sun.COM  * ************************************************************************
6447917SReza.Sabdar@Sun.COM  * NDMP V3 HANDLERS
6457917SReza.Sabdar@Sun.COM  * ************************************************************************
6467917SReza.Sabdar@Sun.COM  */
6477917SReza.Sabdar@Sun.COM 
6487917SReza.Sabdar@Sun.COM /*
6497917SReza.Sabdar@Sun.COM  * ndmpd_tape_open_v3
6507917SReza.Sabdar@Sun.COM  *
6517917SReza.Sabdar@Sun.COM  * This handler opens the specified tape device.
6527917SReza.Sabdar@Sun.COM  *
6537917SReza.Sabdar@Sun.COM  * Parameters:
6547917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
6557917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
6567917SReza.Sabdar@Sun.COM  *
6577917SReza.Sabdar@Sun.COM  * Returns:
6587917SReza.Sabdar@Sun.COM  *   void
6597917SReza.Sabdar@Sun.COM  */
6607917SReza.Sabdar@Sun.COM void
ndmpd_tape_open_v3(ndmp_connection_t * connection,void * body)6617917SReza.Sabdar@Sun.COM ndmpd_tape_open_v3(ndmp_connection_t *connection, void *body)
6627917SReza.Sabdar@Sun.COM {
6637917SReza.Sabdar@Sun.COM 	ndmp_tape_open_request_v3 *request = (ndmp_tape_open_request_v3 *)body;
6647917SReza.Sabdar@Sun.COM 
6657917SReza.Sabdar@Sun.COM 	common_tape_open(connection, request->device, request->mode);
6667917SReza.Sabdar@Sun.COM }
6677917SReza.Sabdar@Sun.COM 
6687917SReza.Sabdar@Sun.COM 
6697917SReza.Sabdar@Sun.COM /*
6707917SReza.Sabdar@Sun.COM  * ndmpd_tape_get_state_v3
6717917SReza.Sabdar@Sun.COM  *
6727917SReza.Sabdar@Sun.COM  * This handler handles the ndmp_tape_get_state_request.
6737917SReza.Sabdar@Sun.COM  * Status information for the currently open tape device is returned.
6747917SReza.Sabdar@Sun.COM  *
6757917SReza.Sabdar@Sun.COM  * Parameters:
6767917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
6777917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
6787917SReza.Sabdar@Sun.COM  *
6797917SReza.Sabdar@Sun.COM  * Returns:
6807917SReza.Sabdar@Sun.COM  *   void
6817917SReza.Sabdar@Sun.COM  */
6827917SReza.Sabdar@Sun.COM /*ARGSUSED*/
6837917SReza.Sabdar@Sun.COM void
ndmpd_tape_get_state_v3(ndmp_connection_t * connection,void * body)6847917SReza.Sabdar@Sun.COM ndmpd_tape_get_state_v3(ndmp_connection_t *connection, void *body)
6857917SReza.Sabdar@Sun.COM {
6867917SReza.Sabdar@Sun.COM 	ndmp_tape_get_state_reply_v3 reply;
6877917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
6887917SReza.Sabdar@Sun.COM 	struct mtdrivetype_request dtpr;
6897917SReza.Sabdar@Sun.COM 	struct mtdrivetype dtp;
6907917SReza.Sabdar@Sun.COM 	struct mtget mtstatus;
6917917SReza.Sabdar@Sun.COM 
6927917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
6937917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
6947917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
6957917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
6967917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
6977917SReza.Sabdar@Sun.COM 		return;
6987917SReza.Sabdar@Sun.COM 	}
6997917SReza.Sabdar@Sun.COM 
7007917SReza.Sabdar@Sun.COM 	if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
7017917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Failed to get status from tape: %m.");
7027917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
7037917SReza.Sabdar@Sun.COM 
7047917SReza.Sabdar@Sun.COM 		reply.error = NDMP_IO_ERR;
7057917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
7067917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
7077917SReza.Sabdar@Sun.COM 		return;
7087917SReza.Sabdar@Sun.COM 	}
7097917SReza.Sabdar@Sun.COM 
7107917SReza.Sabdar@Sun.COM 	dtpr.size = sizeof (struct mtdrivetype);
7117917SReza.Sabdar@Sun.COM 	dtpr.mtdtp = &dtp;
7127917SReza.Sabdar@Sun.COM 	if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
7137917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR,
7147917SReza.Sabdar@Sun.COM 		    "Failed to get drive type information from tape: %m.");
7157917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
7167917SReza.Sabdar@Sun.COM 
7177917SReza.Sabdar@Sun.COM 		reply.error = NDMP_IO_ERR;
7187917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
7197917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
7207917SReza.Sabdar@Sun.COM 		return;
7217917SReza.Sabdar@Sun.COM 	}
7227917SReza.Sabdar@Sun.COM 
7237917SReza.Sabdar@Sun.COM 	reply.flags = 0;
7247917SReza.Sabdar@Sun.COM 
7257917SReza.Sabdar@Sun.COM 	reply.file_num = mtstatus.mt_fileno;
7267917SReza.Sabdar@Sun.COM 	reply.soft_errors = 0;
7277917SReza.Sabdar@Sun.COM 	reply.block_size = dtp.bsize;
7287917SReza.Sabdar@Sun.COM 	if (dtp.bsize == 0)
7297917SReza.Sabdar@Sun.COM 		reply.blockno = mtstatus.mt_blkno;
7307917SReza.Sabdar@Sun.COM 	else
7317917SReza.Sabdar@Sun.COM 		reply.blockno = mtstatus.mt_blkno *
7327917SReza.Sabdar@Sun.COM 		    (session->ns_mover.md_record_size / dtp.bsize);
7337917SReza.Sabdar@Sun.COM 	reply.total_space = long_long_to_quad(0); /* not supported */
7347917SReza.Sabdar@Sun.COM 	reply.space_remain = long_long_to_quad(0); /* not supported */
7357917SReza.Sabdar@Sun.COM 	reply.partition = 0; /* not supported */
7367917SReza.Sabdar@Sun.COM 
7377917SReza.Sabdar@Sun.COM 	reply.soft_errors = 0;
7387917SReza.Sabdar@Sun.COM 	reply.total_space = long_long_to_quad(0LL);
7397917SReza.Sabdar@Sun.COM 	reply.space_remain = long_long_to_quad(0LL);
7407917SReza.Sabdar@Sun.COM 
7417917SReza.Sabdar@Sun.COM 	reply.invalid = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
7427917SReza.Sabdar@Sun.COM 	    NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
7437917SReza.Sabdar@Sun.COM 	    NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
7447917SReza.Sabdar@Sun.COM 	    NDMP_TAPE_STATE_PARTITION_INVALID;
7457917SReza.Sabdar@Sun.COM 
7467917SReza.Sabdar@Sun.COM 
7477917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "f 0x%x, fnum %d, bsize %d, bno: %d",
7487917SReza.Sabdar@Sun.COM 	    reply.flags, reply.file_num, reply.block_size, reply.blockno);
7497917SReza.Sabdar@Sun.COM 
7507917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
7517917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
7527917SReza.Sabdar@Sun.COM 	    "sending tape_get_state reply");
7537917SReza.Sabdar@Sun.COM }
7547917SReza.Sabdar@Sun.COM 
7557917SReza.Sabdar@Sun.COM 
7567917SReza.Sabdar@Sun.COM /*
7577917SReza.Sabdar@Sun.COM  * ndmpd_tape_write_v3
7587917SReza.Sabdar@Sun.COM  *
7597917SReza.Sabdar@Sun.COM  * This handler handles tape_write requests.
7607917SReza.Sabdar@Sun.COM  * This interface is a non-buffered interface. Each write request
7617917SReza.Sabdar@Sun.COM  * maps directly to a write to the tape device. It is the responsibility
7627917SReza.Sabdar@Sun.COM  * of the NDMP client to pad the data to the desired record size.
7637917SReza.Sabdar@Sun.COM  * It is the responsibility of the NDMP client to ensure that the
7647917SReza.Sabdar@Sun.COM  * length is a multiple of the tape block size if the tape device
7657917SReza.Sabdar@Sun.COM  * is in fixed block mode.
7667917SReza.Sabdar@Sun.COM  *
7677917SReza.Sabdar@Sun.COM  * Parameters:
7687917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
7697917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
7707917SReza.Sabdar@Sun.COM  *
7717917SReza.Sabdar@Sun.COM  * Returns:
7727917SReza.Sabdar@Sun.COM  *   void
7737917SReza.Sabdar@Sun.COM  */
7747917SReza.Sabdar@Sun.COM void
ndmpd_tape_write_v3(ndmp_connection_t * connection,void * body)7757917SReza.Sabdar@Sun.COM ndmpd_tape_write_v3(ndmp_connection_t *connection, void *body)
7767917SReza.Sabdar@Sun.COM {
7777917SReza.Sabdar@Sun.COM 	ndmp_tape_write_request *request = (ndmp_tape_write_request *) body;
7787917SReza.Sabdar@Sun.COM 	ndmp_tape_write_reply reply;
7797917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
7807917SReza.Sabdar@Sun.COM 	ssize_t n;
7817917SReza.Sabdar@Sun.COM 
7827917SReza.Sabdar@Sun.COM 	reply.count = 0;
7837917SReza.Sabdar@Sun.COM 
7847917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
7857917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
7867917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
7877917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
7887917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
7897917SReza.Sabdar@Sun.COM 		return;
7907917SReza.Sabdar@Sun.COM 	}
7917917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
7927917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_INFO, "Tape device opened in read-only mode");
7937917SReza.Sabdar@Sun.COM 		reply.error = NDMP_PERMISSION_ERR;
7947917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
7957917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
7967917SReza.Sabdar@Sun.COM 		return;
7977917SReza.Sabdar@Sun.COM 	}
7987917SReza.Sabdar@Sun.COM 	if (request->data_out.data_out_len == 0) {
7997917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
8007917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
8017917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
8027917SReza.Sabdar@Sun.COM 		return;
8037917SReza.Sabdar@Sun.COM 	}
8047917SReza.Sabdar@Sun.COM 
8057917SReza.Sabdar@Sun.COM 	/*
8067917SReza.Sabdar@Sun.COM 	 * V4 suggests that this should not be accepted
8077917SReza.Sabdar@Sun.COM 	 * when mover is in listen or active state
8087917SReza.Sabdar@Sun.COM 	 */
8097917SReza.Sabdar@Sun.COM 	if (session->ns_protocol_version == NDMPV4 &&
8107917SReza.Sabdar@Sun.COM 	    (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
8117917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
8127917SReza.Sabdar@Sun.COM 
8137917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEVICE_BUSY_ERR;
8147917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
8157917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
8167917SReza.Sabdar@Sun.COM 		return;
8177917SReza.Sabdar@Sun.COM 	}
8187917SReza.Sabdar@Sun.COM 
8197917SReza.Sabdar@Sun.COM 	/*
8207917SReza.Sabdar@Sun.COM 	 * Refer to the comment at the top of this file for
8217917SReza.Sabdar@Sun.COM 	 * Mammoth2 tape drives.
8227917SReza.Sabdar@Sun.COM 	 */
8237917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_eom_seen) {
8247917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "eom_seen");
8257917SReza.Sabdar@Sun.COM 		ndmpd_write_eom(session->ns_tape.td_fd);
8267917SReza.Sabdar@Sun.COM 		session->ns_tape.td_eom_seen = FALSE;
8277917SReza.Sabdar@Sun.COM 		reply.error = NDMP_EOM_ERR;
8287917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
8297917SReza.Sabdar@Sun.COM 		    "sending tape_write reply");
8307917SReza.Sabdar@Sun.COM 		return;
8317917SReza.Sabdar@Sun.COM 	}
8327917SReza.Sabdar@Sun.COM 
8337917SReza.Sabdar@Sun.COM 	n = write(session->ns_tape.td_fd, request->data_out.data_out_val,
8347917SReza.Sabdar@Sun.COM 	    request->data_out.data_out_len);
8357917SReza.Sabdar@Sun.COM 
8367917SReza.Sabdar@Sun.COM 	session->ns_tape.td_eom_seen = FALSE;
8377917SReza.Sabdar@Sun.COM 	if (n >= 0) {
8387917SReza.Sabdar@Sun.COM 		session->ns_tape.td_write = 1;
8397917SReza.Sabdar@Sun.COM 		NS_ADD(wtape, n);
8407917SReza.Sabdar@Sun.COM 	}
8417917SReza.Sabdar@Sun.COM 	if (n == 0) {
8427917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_INFO, "EOM detected");
8437917SReza.Sabdar@Sun.COM 		reply.error = NDMP_EOM_ERR;
8447917SReza.Sabdar@Sun.COM 		session->ns_tape.td_eom_seen = TRUE;
8457917SReza.Sabdar@Sun.COM 	} else if (n < 0) {
8467917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
8477917SReza.Sabdar@Sun.COM 		reply.error = NDMP_IO_ERR;
8487917SReza.Sabdar@Sun.COM 	} else {
8497917SReza.Sabdar@Sun.COM 		reply.count = n;
8507917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
8517917SReza.Sabdar@Sun.COM 	}
8527917SReza.Sabdar@Sun.COM 
8537917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
8547917SReza.Sabdar@Sun.COM 	    "sending tape_write reply");
8557917SReza.Sabdar@Sun.COM }
8567917SReza.Sabdar@Sun.COM 
8577917SReza.Sabdar@Sun.COM 
8587917SReza.Sabdar@Sun.COM /*
8597917SReza.Sabdar@Sun.COM  * ndmpd_tape_read_v3
8607917SReza.Sabdar@Sun.COM  *
8617917SReza.Sabdar@Sun.COM  * This handler handles tape_read requests.
8627917SReza.Sabdar@Sun.COM  * This interface is a non-buffered interface. Each read request
8637917SReza.Sabdar@Sun.COM  * maps directly to a read to the tape device. It is the responsibility
8647917SReza.Sabdar@Sun.COM  * of the NDMP client to issue read requests with a length that is at
8657917SReza.Sabdar@Sun.COM  * least as large as the record size used write the tape. The tape driver
8667917SReza.Sabdar@Sun.COM  * always reads a full record. Data is discarded if the read request is
8677917SReza.Sabdar@Sun.COM  * smaller than the record size.
8687917SReza.Sabdar@Sun.COM  * It is the responsibility of the NDMP client to ensure that the
8697917SReza.Sabdar@Sun.COM  * length is a multiple of the tape block size if the tape device
8707917SReza.Sabdar@Sun.COM  * is in fixed block mode.
8717917SReza.Sabdar@Sun.COM  *
8727917SReza.Sabdar@Sun.COM  * Parameters:
8737917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
8747917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
8757917SReza.Sabdar@Sun.COM  *
8767917SReza.Sabdar@Sun.COM  * Returns:
8777917SReza.Sabdar@Sun.COM  *   void
8787917SReza.Sabdar@Sun.COM  */
8797917SReza.Sabdar@Sun.COM void
ndmpd_tape_read_v3(ndmp_connection_t * connection,void * body)8807917SReza.Sabdar@Sun.COM ndmpd_tape_read_v3(ndmp_connection_t *connection, void *body)
8817917SReza.Sabdar@Sun.COM {
8827917SReza.Sabdar@Sun.COM 	ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
8837917SReza.Sabdar@Sun.COM 	ndmp_tape_read_reply reply;
8847917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
8857917SReza.Sabdar@Sun.COM 	char *buf;
8867917SReza.Sabdar@Sun.COM 	int n, len;
8877917SReza.Sabdar@Sun.COM 
8887917SReza.Sabdar@Sun.COM 	reply.data_in.data_in_len = 0;
8897917SReza.Sabdar@Sun.COM 
8907917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
8917917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
8927917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
8937917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
8947917SReza.Sabdar@Sun.COM 		    "sending tape_read reply");
8957917SReza.Sabdar@Sun.COM 		return;
8967917SReza.Sabdar@Sun.COM 	}
8977917SReza.Sabdar@Sun.COM 	if (request->count == 0) {
8987917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
8997917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
9007917SReza.Sabdar@Sun.COM 		    "sending tape_read reply");
9017917SReza.Sabdar@Sun.COM 		return;
9027917SReza.Sabdar@Sun.COM 	}
9037917SReza.Sabdar@Sun.COM 
9047917SReza.Sabdar@Sun.COM 	/*
9057917SReza.Sabdar@Sun.COM 	 * V4 suggests that this should not be accepted
9067917SReza.Sabdar@Sun.COM 	 * when mover is in listen or active state
9077917SReza.Sabdar@Sun.COM 	 */
9087917SReza.Sabdar@Sun.COM 	if (session->ns_protocol_version == NDMPV4 &&
9097917SReza.Sabdar@Sun.COM 	    (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
9107917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
9117917SReza.Sabdar@Sun.COM 
9127917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEVICE_BUSY_ERR;
9137917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
9147917SReza.Sabdar@Sun.COM 		    "sending tape_read reply");
9157917SReza.Sabdar@Sun.COM 		return;
9167917SReza.Sabdar@Sun.COM 	}
9177917SReza.Sabdar@Sun.COM 
9187917SReza.Sabdar@Sun.COM 	if ((buf = ndmp_malloc(request->count)) == NULL) {
9197917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_MEM_ERR;
9207917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
9217917SReza.Sabdar@Sun.COM 		    "sending tape_read reply");
9227917SReza.Sabdar@Sun.COM 		return;
9237917SReza.Sabdar@Sun.COM 	}
9247917SReza.Sabdar@Sun.COM 	session->ns_tape.td_eom_seen = FALSE;
9257917SReza.Sabdar@Sun.COM 
9267917SReza.Sabdar@Sun.COM 	n = read(session->ns_tape.td_fd, buf, request->count);
9277917SReza.Sabdar@Sun.COM 	if (n < 0) {
9287917SReza.Sabdar@Sun.COM 		/*
9297917SReza.Sabdar@Sun.COM 		 * This fix is for Symantec during importing
9307917SReza.Sabdar@Sun.COM 		 * of spanned data between the tapes.
9317917SReza.Sabdar@Sun.COM 		 */
9327917SReza.Sabdar@Sun.COM 		if (errno == ENOSPC) {
9337917SReza.Sabdar@Sun.COM 			reply.error = NDMP_EOF_ERR;
9347917SReza.Sabdar@Sun.COM 		} else {
9357917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
9367917SReza.Sabdar@Sun.COM 			reply.error = NDMP_IO_ERR;
9377917SReza.Sabdar@Sun.COM 		}
9387917SReza.Sabdar@Sun.COM 	} else if (n == 0) {
9397917SReza.Sabdar@Sun.COM 		(void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
9407917SReza.Sabdar@Sun.COM 
9417917SReza.Sabdar@Sun.COM 		len = strlen(NDMP_EOM_MAGIC);
9427917SReza.Sabdar@Sun.COM 		(void) memset(buf, 0, len);
9437917SReza.Sabdar@Sun.COM 		n = read(session->ns_tape.td_fd, buf, len);
9447917SReza.Sabdar@Sun.COM 		buf[len] = '\0';
9457917SReza.Sabdar@Sun.COM 
9467917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Checking EOM: nread %d [%s]", n, buf);
9477917SReza.Sabdar@Sun.COM 
948*9169SReza.Sabdar@Sun.COM 		if (strncmp(buf, NDMP_EOM_MAGIC, len) == 0) {
9497917SReza.Sabdar@Sun.COM 			reply.error = NDMP_EOM_ERR;
9507917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "NDMP_EOM_ERR");
9517917SReza.Sabdar@Sun.COM 		} else {
9527917SReza.Sabdar@Sun.COM 			reply.error = NDMP_EOF_ERR;
9537917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "NDMP_EOF_ERR");
9547917SReza.Sabdar@Sun.COM 		}
9557917SReza.Sabdar@Sun.COM 		if (n > 0)
9567917SReza.Sabdar@Sun.COM 			(void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSR, 1);
9577917SReza.Sabdar@Sun.COM 	} else {
9587917SReza.Sabdar@Sun.COM 		/*
9597917SReza.Sabdar@Sun.COM 		 * Symantec fix for import phase
9607917SReza.Sabdar@Sun.COM 		 *
9617917SReza.Sabdar@Sun.COM 		 * As import process from symantec skips filemarks
9627917SReza.Sabdar@Sun.COM 		 * they can come across to NDMP_EOM_MAGIC and treat
9637917SReza.Sabdar@Sun.COM 		 * it as data. This fix prevents the magic to be
9647917SReza.Sabdar@Sun.COM 		 * sent to the client and the read will return zero bytes
9657917SReza.Sabdar@Sun.COM 		 * and set the NDMP_EOM_ERR error. The tape should
9667917SReza.Sabdar@Sun.COM 		 * be positioned at the EOT side of the file mark.
9677917SReza.Sabdar@Sun.COM 		 */
9687917SReza.Sabdar@Sun.COM 		len = strlen(NDMP_EOM_MAGIC);
9697917SReza.Sabdar@Sun.COM 		if (n == len && strncmp(buf, NDMP_EOM_MAGIC, len) == 0) {
9707917SReza.Sabdar@Sun.COM 			reply.error = NDMP_EOM_ERR;
9717917SReza.Sabdar@Sun.COM 			(void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
9727917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "NDMP_EOM_ERR");
9737917SReza.Sabdar@Sun.COM 		} else {
9747917SReza.Sabdar@Sun.COM 			session->ns_tape.td_pos += n;
9757917SReza.Sabdar@Sun.COM 			reply.data_in.data_in_len = n;
9767917SReza.Sabdar@Sun.COM 			reply.data_in.data_in_val = buf;
9777917SReza.Sabdar@Sun.COM 			reply.error = NDMP_NO_ERR;
9787917SReza.Sabdar@Sun.COM 		}
9797917SReza.Sabdar@Sun.COM 		NS_ADD(rtape, n);
9807917SReza.Sabdar@Sun.COM 	}
9817917SReza.Sabdar@Sun.COM 
9827917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
9837917SReza.Sabdar@Sun.COM 	free(buf);
9847917SReza.Sabdar@Sun.COM }
9857917SReza.Sabdar@Sun.COM 
9867917SReza.Sabdar@Sun.COM 
9877917SReza.Sabdar@Sun.COM /*
9887917SReza.Sabdar@Sun.COM  * ************************************************************************
9897917SReza.Sabdar@Sun.COM  * NDMP V4 HANDLERS
9907917SReza.Sabdar@Sun.COM  * ************************************************************************
9917917SReza.Sabdar@Sun.COM  */
9927917SReza.Sabdar@Sun.COM 
9937917SReza.Sabdar@Sun.COM /*
9947917SReza.Sabdar@Sun.COM  * ndmpd_tape_get_state_v4
9957917SReza.Sabdar@Sun.COM  *
9967917SReza.Sabdar@Sun.COM  * This handler handles the ndmp_tape_get_state_request.
9977917SReza.Sabdar@Sun.COM  * Status information for the currently open tape device is returned.
9987917SReza.Sabdar@Sun.COM  *
9997917SReza.Sabdar@Sun.COM  * Parameters:
10007917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
10017917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
10027917SReza.Sabdar@Sun.COM  *
10037917SReza.Sabdar@Sun.COM  * Returns:
10047917SReza.Sabdar@Sun.COM  *   void
10057917SReza.Sabdar@Sun.COM  */
10067917SReza.Sabdar@Sun.COM /*ARGSUSED*/
10077917SReza.Sabdar@Sun.COM void
ndmpd_tape_get_state_v4(ndmp_connection_t * connection,void * body)10087917SReza.Sabdar@Sun.COM ndmpd_tape_get_state_v4(ndmp_connection_t *connection, void *body)
10097917SReza.Sabdar@Sun.COM {
10107917SReza.Sabdar@Sun.COM 	ndmp_tape_get_state_reply_v4 reply;
10117917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
10127917SReza.Sabdar@Sun.COM 	struct mtget mtstatus;
10137917SReza.Sabdar@Sun.COM 	struct mtdrivetype_request dtpr;
10147917SReza.Sabdar@Sun.COM 	struct mtdrivetype dtp;
10157917SReza.Sabdar@Sun.COM 
10167917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
10177917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
10187917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
10197917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
10207917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
10217917SReza.Sabdar@Sun.COM 		return;
10227917SReza.Sabdar@Sun.COM 	}
10237917SReza.Sabdar@Sun.COM 
10247917SReza.Sabdar@Sun.COM 	/*
10257917SReza.Sabdar@Sun.COM 	 * Need code to detect NDMP_TAPE_STATE_NOREWIND
10267917SReza.Sabdar@Sun.COM 	 */
10277917SReza.Sabdar@Sun.COM 
10287917SReza.Sabdar@Sun.COM 	if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
10297917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR,
10307917SReza.Sabdar@Sun.COM 		    "Failed to get status information from tape: %m.");
10317917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
10327917SReza.Sabdar@Sun.COM 
10337917SReza.Sabdar@Sun.COM 		reply.error = NDMP_IO_ERR;
10347917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
10357917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
10367917SReza.Sabdar@Sun.COM 		return;
10377917SReza.Sabdar@Sun.COM 	}
10387917SReza.Sabdar@Sun.COM 
10397917SReza.Sabdar@Sun.COM 	dtpr.size = sizeof (struct mtdrivetype);
10407917SReza.Sabdar@Sun.COM 	dtpr.mtdtp = &dtp;
10417917SReza.Sabdar@Sun.COM 	if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
10427917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR,
10437917SReza.Sabdar@Sun.COM 		    "Failed to get drive type information from tape: %m.");
10447917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
10457917SReza.Sabdar@Sun.COM 
10467917SReza.Sabdar@Sun.COM 		reply.error = NDMP_IO_ERR;
10477917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *)&reply,
10487917SReza.Sabdar@Sun.COM 		    "sending tape_get_state reply");
10497917SReza.Sabdar@Sun.COM 		return;
10507917SReza.Sabdar@Sun.COM 	}
10517917SReza.Sabdar@Sun.COM 
10528800SReza.Sabdar@Sun.COM 	reply.flags = NDMP_TAPE_NOREWIND;
10537917SReza.Sabdar@Sun.COM 
10547917SReza.Sabdar@Sun.COM 	reply.file_num = mtstatus.mt_fileno;
10557917SReza.Sabdar@Sun.COM 	reply.soft_errors = 0;
10567917SReza.Sabdar@Sun.COM 	reply.block_size = dtp.bsize;
10577917SReza.Sabdar@Sun.COM 
10587917SReza.Sabdar@Sun.COM 	if (dtp.bsize == 0)
10597917SReza.Sabdar@Sun.COM 		reply.blockno = mtstatus.mt_blkno;
10607917SReza.Sabdar@Sun.COM 	else
10617917SReza.Sabdar@Sun.COM 		reply.blockno = mtstatus.mt_blkno *
10627917SReza.Sabdar@Sun.COM 		    (session->ns_mover.md_record_size / dtp.bsize);
10637917SReza.Sabdar@Sun.COM 
10647917SReza.Sabdar@Sun.COM 	reply.total_space = long_long_to_quad(0); /* not supported */
10657917SReza.Sabdar@Sun.COM 	reply.space_remain = long_long_to_quad(0); /* not supported */
10667917SReza.Sabdar@Sun.COM 
10677917SReza.Sabdar@Sun.COM 	reply.soft_errors = 0;
10687917SReza.Sabdar@Sun.COM 	reply.total_space = long_long_to_quad(0LL);
10697917SReza.Sabdar@Sun.COM 	reply.space_remain = long_long_to_quad(0LL);
10707917SReza.Sabdar@Sun.COM 	reply.unsupported = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
10717917SReza.Sabdar@Sun.COM 	    NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
10727917SReza.Sabdar@Sun.COM 	    NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
10737917SReza.Sabdar@Sun.COM 	    NDMP_TAPE_STATE_PARTITION_INVALID;
10747917SReza.Sabdar@Sun.COM 
10757917SReza.Sabdar@Sun.COM 
10767917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "f 0x%x, fnum %d, bsize %d, bno: %d",
10777917SReza.Sabdar@Sun.COM 	    reply.flags, reply.file_num, reply.block_size, reply.blockno);
10787917SReza.Sabdar@Sun.COM 
10797917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
10807917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
10817917SReza.Sabdar@Sun.COM 	    "sending tape_get_state reply");
10827917SReza.Sabdar@Sun.COM }
10837917SReza.Sabdar@Sun.COM /*
10847917SReza.Sabdar@Sun.COM  * ndmpd_tape_close_v4
10857917SReza.Sabdar@Sun.COM  *
10867917SReza.Sabdar@Sun.COM  * This handler (v4) closes the currently open tape device.
10877917SReza.Sabdar@Sun.COM  *
10887917SReza.Sabdar@Sun.COM  * Parameters:
10897917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
10907917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
10917917SReza.Sabdar@Sun.COM  *
10927917SReza.Sabdar@Sun.COM  * Returns:
10937917SReza.Sabdar@Sun.COM  *   void
10947917SReza.Sabdar@Sun.COM  */
10957917SReza.Sabdar@Sun.COM /*ARGSUSED*/
10967917SReza.Sabdar@Sun.COM void
ndmpd_tape_close_v4(ndmp_connection_t * connection,void * body)10977917SReza.Sabdar@Sun.COM ndmpd_tape_close_v4(ndmp_connection_t *connection, void *body)
10987917SReza.Sabdar@Sun.COM {
10997917SReza.Sabdar@Sun.COM 	ndmp_tape_close_reply reply;
11007917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
11017917SReza.Sabdar@Sun.COM 
11027917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
11037917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape device is not open.");
11047917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
11057917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
11067917SReza.Sabdar@Sun.COM 		    "sending tape_close reply");
11077917SReza.Sabdar@Sun.COM 		return;
11087917SReza.Sabdar@Sun.COM 	}
11097917SReza.Sabdar@Sun.COM 
11107917SReza.Sabdar@Sun.COM 	/*
11117917SReza.Sabdar@Sun.COM 	 * V4 suggests that this should not be accepted
11127917SReza.Sabdar@Sun.COM 	 * when mover is in listen or active state
11137917SReza.Sabdar@Sun.COM 	 */
11147917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
11157917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
11167917SReza.Sabdar@Sun.COM 
11177917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEVICE_BUSY_ERR;
11187917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
11197917SReza.Sabdar@Sun.COM 		    "sending tape_close reply");
11207917SReza.Sabdar@Sun.COM 		return;
11217917SReza.Sabdar@Sun.COM 	}
11227917SReza.Sabdar@Sun.COM 
11237917SReza.Sabdar@Sun.COM 	common_tape_close(connection);
11247917SReza.Sabdar@Sun.COM }
11257917SReza.Sabdar@Sun.COM 
11267917SReza.Sabdar@Sun.COM 
11277917SReza.Sabdar@Sun.COM /*
11287917SReza.Sabdar@Sun.COM  * ************************************************************************
11297917SReza.Sabdar@Sun.COM  * LOCALS
11307917SReza.Sabdar@Sun.COM  * ************************************************************************
11317917SReza.Sabdar@Sun.COM  */
11327917SReza.Sabdar@Sun.COM /*
11337917SReza.Sabdar@Sun.COM  * tape_open_send_reply
11347917SReza.Sabdar@Sun.COM  *
11357917SReza.Sabdar@Sun.COM  * Send a reply to the tape open message
11367917SReza.Sabdar@Sun.COM  *
11377917SReza.Sabdar@Sun.COM  * Parameters:
11387917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
11397917SReza.Sabdar@Sun.COM  *   err (input) - NDMP error
11407917SReza.Sabdar@Sun.COM  *
11417917SReza.Sabdar@Sun.COM  * Returns:
11427917SReza.Sabdar@Sun.COM  *   void
11437917SReza.Sabdar@Sun.COM  */
11447917SReza.Sabdar@Sun.COM static void
tape_open_send_reply(ndmp_connection_t * connection,int err)11457917SReza.Sabdar@Sun.COM tape_open_send_reply(ndmp_connection_t *connection, int err)
11467917SReza.Sabdar@Sun.COM {
11477917SReza.Sabdar@Sun.COM 	ndmp_tape_open_reply reply;
11487917SReza.Sabdar@Sun.COM 
11497917SReza.Sabdar@Sun.COM 	reply.error = err;
11507917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply, "sending tape_open reply");
11517917SReza.Sabdar@Sun.COM }
11527917SReza.Sabdar@Sun.COM 
11537917SReza.Sabdar@Sun.COM /*
11547917SReza.Sabdar@Sun.COM  * unbuffered_read
11557917SReza.Sabdar@Sun.COM  *
11567917SReza.Sabdar@Sun.COM  * Perform tape read without read-ahead
11577917SReza.Sabdar@Sun.COM  *
11587917SReza.Sabdar@Sun.COM  * Parameters:
11597917SReza.Sabdar@Sun.COM  *   session (input) - session handle
11607917SReza.Sabdar@Sun.COM  *   bp (output) - read buffer
11617917SReza.Sabdar@Sun.COM  *   wanted (input) - number of bytes wanted
11627917SReza.Sabdar@Sun.COM  *   reply (output) - tape read reply message
11637917SReza.Sabdar@Sun.COM  *
11647917SReza.Sabdar@Sun.COM  * Returns:
11657917SReza.Sabdar@Sun.COM  *   void
11667917SReza.Sabdar@Sun.COM  */
11677917SReza.Sabdar@Sun.COM static void
unbuffered_read(ndmpd_session_t * session,char * buf,long wanted,ndmp_tape_read_reply * reply)11687917SReza.Sabdar@Sun.COM unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
11697917SReza.Sabdar@Sun.COM     ndmp_tape_read_reply *reply)
11707917SReza.Sabdar@Sun.COM {
11717917SReza.Sabdar@Sun.COM 	int n, len;
11727917SReza.Sabdar@Sun.COM 
11737917SReza.Sabdar@Sun.COM 	n = read(session->ns_tape.td_fd, buf, wanted);
11747917SReza.Sabdar@Sun.COM 	if (n < 0) {
11757917SReza.Sabdar@Sun.COM 		/*
11767917SReza.Sabdar@Sun.COM 		 * This fix is for Symantec during importing
11777917SReza.Sabdar@Sun.COM 		 * of spanned data between the tapes.
11787917SReza.Sabdar@Sun.COM 		 */
11797917SReza.Sabdar@Sun.COM 		if (errno == ENOSPC) {
11807917SReza.Sabdar@Sun.COM 			reply->error = NDMP_EOF_ERR;
11817917SReza.Sabdar@Sun.COM 		} else {
11827917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
11837917SReza.Sabdar@Sun.COM 			reply->error = NDMP_IO_ERR;
11847917SReza.Sabdar@Sun.COM 		}
11857917SReza.Sabdar@Sun.COM 	} else if (n == 0) {
11867917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "NDMP_EOF_ERR");
11877917SReza.Sabdar@Sun.COM 
11887917SReza.Sabdar@Sun.COM 		reply->error = NDMP_EOF_ERR;
11897917SReza.Sabdar@Sun.COM 
11907917SReza.Sabdar@Sun.COM 		(void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
11917917SReza.Sabdar@Sun.COM 
11927917SReza.Sabdar@Sun.COM 		len = strlen(NDMP_EOM_MAGIC);
11937917SReza.Sabdar@Sun.COM 		(void) memset(buf, 0, len);
11947917SReza.Sabdar@Sun.COM 		n = read(session->ns_tape.td_fd, buf, len);
11957917SReza.Sabdar@Sun.COM 		buf[len] = '\0';
11967917SReza.Sabdar@Sun.COM 
11977917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Checking EOM: nread %d [%s]", n, buf);
11987917SReza.Sabdar@Sun.COM 
11997917SReza.Sabdar@Sun.COM 		(void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
12007917SReza.Sabdar@Sun.COM 
12017917SReza.Sabdar@Sun.COM 		if (strncmp(buf, NDMP_EOM_MAGIC, len) != 0)
12027917SReza.Sabdar@Sun.COM 			(void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
12037917SReza.Sabdar@Sun.COM 	} else {
12047917SReza.Sabdar@Sun.COM 		session->ns_tape.td_pos += n;
12057917SReza.Sabdar@Sun.COM 		reply->data_in.data_in_len = n;
12067917SReza.Sabdar@Sun.COM 		reply->data_in.data_in_val = buf;
12077917SReza.Sabdar@Sun.COM 		reply->error = NDMP_NO_ERR;
12087917SReza.Sabdar@Sun.COM 		NS_ADD(rtape, n);
12097917SReza.Sabdar@Sun.COM 	}
12107917SReza.Sabdar@Sun.COM }
12117917SReza.Sabdar@Sun.COM 
12127917SReza.Sabdar@Sun.COM 
12137917SReza.Sabdar@Sun.COM /*
12147917SReza.Sabdar@Sun.COM  * validmode
12157917SReza.Sabdar@Sun.COM  *
12167917SReza.Sabdar@Sun.COM  * Check the tape read mode is valid
12177917SReza.Sabdar@Sun.COM  */
12187917SReza.Sabdar@Sun.COM static boolean_t
validmode(int mode)12197917SReza.Sabdar@Sun.COM validmode(int mode)
12207917SReza.Sabdar@Sun.COM {
12217917SReza.Sabdar@Sun.COM 	boolean_t rv;
12227917SReza.Sabdar@Sun.COM 
12237917SReza.Sabdar@Sun.COM 	switch (mode) {
12247917SReza.Sabdar@Sun.COM 	case NDMP_TAPE_READ_MODE:
12257917SReza.Sabdar@Sun.COM 	case NDMP_TAPE_WRITE_MODE:
12267917SReza.Sabdar@Sun.COM 	case NDMP_TAPE_RAW1_MODE:
12277917SReza.Sabdar@Sun.COM 	case NDMP_TAPE_RAW2_MODE:
12287917SReza.Sabdar@Sun.COM 		rv = TRUE;
12297917SReza.Sabdar@Sun.COM 		break;
12307917SReza.Sabdar@Sun.COM 	default:
12317917SReza.Sabdar@Sun.COM 		rv = FALSE;
12327917SReza.Sabdar@Sun.COM 	}
12337917SReza.Sabdar@Sun.COM 
12347917SReza.Sabdar@Sun.COM 	return (rv);
12357917SReza.Sabdar@Sun.COM }
12367917SReza.Sabdar@Sun.COM 
12377917SReza.Sabdar@Sun.COM 
12387917SReza.Sabdar@Sun.COM /*
12397917SReza.Sabdar@Sun.COM  * common_tape_open
12407917SReza.Sabdar@Sun.COM  *
12417917SReza.Sabdar@Sun.COM  * Generic function for opening the tape for all versions
12427917SReza.Sabdar@Sun.COM  *
12437917SReza.Sabdar@Sun.COM  * Parameters:
12447917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
12457917SReza.Sabdar@Sun.COM  *   devname (input) - tape device name to open.
12467917SReza.Sabdar@Sun.COM  *   ndmpmode (input) - mode of opening (read, write, raw)
12477917SReza.Sabdar@Sun.COM  *
12487917SReza.Sabdar@Sun.COM  * Returns:
12497917SReza.Sabdar@Sun.COM  *   void
12507917SReza.Sabdar@Sun.COM  */
12517917SReza.Sabdar@Sun.COM static void
common_tape_open(ndmp_connection_t * connection,char * devname,int ndmpmode)12527917SReza.Sabdar@Sun.COM common_tape_open(ndmp_connection_t *connection, char *devname, int ndmpmode)
12537917SReza.Sabdar@Sun.COM {
12547917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
12557917SReza.Sabdar@Sun.COM 	char adptnm[SCSI_MAX_NAME];
12567917SReza.Sabdar@Sun.COM 	int err;
12577917SReza.Sabdar@Sun.COM 	int mode;
12587917SReza.Sabdar@Sun.COM 	int sid, lun;
12597917SReza.Sabdar@Sun.COM 	scsi_adapter_t *sa;
12607917SReza.Sabdar@Sun.COM 	int devid;
12617917SReza.Sabdar@Sun.COM 
12627917SReza.Sabdar@Sun.COM 	err = NDMP_NO_ERR;
12637917SReza.Sabdar@Sun.COM 
12647917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
12657917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_INFO,
12667917SReza.Sabdar@Sun.COM 		    "Connection already has a tape or scsi device open");
12677917SReza.Sabdar@Sun.COM 		err = NDMP_DEVICE_OPENED_ERR;
12687917SReza.Sabdar@Sun.COM 	} else if (!validmode(ndmpmode))
12697917SReza.Sabdar@Sun.COM 		err = NDMP_ILLEGAL_ARGS_ERR;
12707917SReza.Sabdar@Sun.COM 	if ((sa = scsi_get_adapter(0)) != NULL) {
12717917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Adapter device opened: %s", devname);
12727917SReza.Sabdar@Sun.COM 		(void) strlcpy(adptnm, devname, SCSI_MAX_NAME-2);
12737917SReza.Sabdar@Sun.COM 		adptnm[SCSI_MAX_NAME-1] = '\0';
12747917SReza.Sabdar@Sun.COM 		sid = lun = -1;
12757917SReza.Sabdar@Sun.COM 	}
12767917SReza.Sabdar@Sun.COM 	if (sa) {
12777917SReza.Sabdar@Sun.COM 		scsi_find_sid_lun(sa, devname, &sid, &lun);
12787917SReza.Sabdar@Sun.COM 		if (ndmp_open_list_find(devname, sid, lun) == 0 &&
12797917SReza.Sabdar@Sun.COM 		    (devid = open(devname, O_RDWR | O_NDELAY)) < 0) {
12807917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR,
12817917SReza.Sabdar@Sun.COM 			    "Failed to open device %s: %m.", devname);
12827917SReza.Sabdar@Sun.COM 			err = NDMP_NO_DEVICE_ERR;
12837917SReza.Sabdar@Sun.COM 		} else {
12847917SReza.Sabdar@Sun.COM 			(void) close(devid);
12857917SReza.Sabdar@Sun.COM 		}
12867917SReza.Sabdar@Sun.COM 	} else {
12877917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "%s: No such tape device.", devname);
12887917SReza.Sabdar@Sun.COM 		err = NDMP_NO_DEVICE_ERR;
12897917SReza.Sabdar@Sun.COM 	}
12907917SReza.Sabdar@Sun.COM 
12917917SReza.Sabdar@Sun.COM 	if (err != NDMP_NO_ERR) {
12927917SReza.Sabdar@Sun.COM 		tape_open_send_reply(connection, err);
12937917SReza.Sabdar@Sun.COM 		return;
12947917SReza.Sabdar@Sun.COM 	}
12957917SReza.Sabdar@Sun.COM 
12967917SReza.Sabdar@Sun.COM 	/*
12977917SReza.Sabdar@Sun.COM 	 * If tape is not opened in raw mode and tape is not loaded
12987917SReza.Sabdar@Sun.COM 	 * return error.
12997917SReza.Sabdar@Sun.COM 	 */
13007917SReza.Sabdar@Sun.COM 	if (ndmpmode != NDMP_TAPE_RAW1_MODE &&
13017917SReza.Sabdar@Sun.COM 	    ndmpmode != NDMP_TAPE_RAW2_MODE &&
13027917SReza.Sabdar@Sun.COM 	    !is_tape_unit_ready(adptnm, 0)) {
13037917SReza.Sabdar@Sun.COM 		tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
13047917SReza.Sabdar@Sun.COM 		return;
13057917SReza.Sabdar@Sun.COM 	}
13067917SReza.Sabdar@Sun.COM 
13077917SReza.Sabdar@Sun.COM 	mode = (ndmpmode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
13087917SReza.Sabdar@Sun.COM 	mode |= O_NDELAY;
13097917SReza.Sabdar@Sun.COM 	session->ns_tape.td_fd = open(devname, mode);
13107917SReza.Sabdar@Sun.COM 	if (session->ns_protocol_version == NDMPV4 &&
13117917SReza.Sabdar@Sun.COM 	    session->ns_tape.td_fd < 0 &&
13127917SReza.Sabdar@Sun.COM 	    ndmpmode == NDMP_TAPE_RAW_MODE && errno == EACCES) {
13137917SReza.Sabdar@Sun.COM 		/*
13147917SReza.Sabdar@Sun.COM 		 * V4 suggests that if the tape is open in raw mode
13157917SReza.Sabdar@Sun.COM 		 * and could not be opened with write access, it should
13167917SReza.Sabdar@Sun.COM 		 * be opened read only instead.
13177917SReza.Sabdar@Sun.COM 		 */
13187917SReza.Sabdar@Sun.COM 		ndmpmode = NDMP_TAPE_READ_MODE;
13197917SReza.Sabdar@Sun.COM 		session->ns_tape.td_fd = open(devname, O_RDONLY);
13207917SReza.Sabdar@Sun.COM 	}
13217917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd < 0) {
13227917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
13237917SReza.Sabdar@Sun.COM 		    devname);
13247917SReza.Sabdar@Sun.COM 		switch (errno) {
13257917SReza.Sabdar@Sun.COM 		case EACCES:
13267917SReza.Sabdar@Sun.COM 			err = NDMP_WRITE_PROTECT_ERR;
13277917SReza.Sabdar@Sun.COM 			break;
13287917SReza.Sabdar@Sun.COM 		case ENOENT:
13297917SReza.Sabdar@Sun.COM 			err = NDMP_NO_DEVICE_ERR;
13307917SReza.Sabdar@Sun.COM 			break;
13317917SReza.Sabdar@Sun.COM 		case EBUSY:
13327917SReza.Sabdar@Sun.COM 			err = NDMP_DEVICE_BUSY_ERR;
13337917SReza.Sabdar@Sun.COM 			break;
13347917SReza.Sabdar@Sun.COM 		case EPERM:
13357917SReza.Sabdar@Sun.COM 			err = NDMP_PERMISSION_ERR;
13367917SReza.Sabdar@Sun.COM 			break;
13377917SReza.Sabdar@Sun.COM 		default:
13387917SReza.Sabdar@Sun.COM 			err = NDMP_IO_ERR;
13397917SReza.Sabdar@Sun.COM 		}
13407917SReza.Sabdar@Sun.COM 
13417917SReza.Sabdar@Sun.COM 		tape_open_send_reply(connection, err);
13427917SReza.Sabdar@Sun.COM 		return;
13437917SReza.Sabdar@Sun.COM 	}
13447917SReza.Sabdar@Sun.COM 
13457917SReza.Sabdar@Sun.COM 	switch (ndmp_open_list_add(connection,
13467917SReza.Sabdar@Sun.COM 	    adptnm, sid, lun, session->ns_tape.td_fd)) {
13477917SReza.Sabdar@Sun.COM 	case 0:
13487917SReza.Sabdar@Sun.COM 		err = NDMP_NO_ERR;
13497917SReza.Sabdar@Sun.COM 		break;
13507917SReza.Sabdar@Sun.COM 	case EBUSY:
13517917SReza.Sabdar@Sun.COM 		err = NDMP_DEVICE_BUSY_ERR;
13527917SReza.Sabdar@Sun.COM 		break;
13537917SReza.Sabdar@Sun.COM 	case ENOMEM:
13547917SReza.Sabdar@Sun.COM 		err = NDMP_NO_MEM_ERR;
13557917SReza.Sabdar@Sun.COM 		break;
13567917SReza.Sabdar@Sun.COM 	default:
13577917SReza.Sabdar@Sun.COM 		err = NDMP_IO_ERR;
13587917SReza.Sabdar@Sun.COM 	}
13597917SReza.Sabdar@Sun.COM 	if (err != NDMP_NO_ERR) {
13607917SReza.Sabdar@Sun.COM 		tape_open_send_reply(connection, err);
13617917SReza.Sabdar@Sun.COM 		return;
13627917SReza.Sabdar@Sun.COM 	}
13637917SReza.Sabdar@Sun.COM 
13647917SReza.Sabdar@Sun.COM 	session->ns_tape.td_mode = ndmpmode;
13657917SReza.Sabdar@Sun.COM 	session->ns_tape.td_sid = sid;
13667917SReza.Sabdar@Sun.COM 	session->ns_tape.td_lun = lun;
13677917SReza.Sabdar@Sun.COM 	(void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
13687917SReza.Sabdar@Sun.COM 	session->ns_tape.td_record_count = 0;
13697917SReza.Sabdar@Sun.COM 	session->ns_tape.td_eom_seen = FALSE;
13707917SReza.Sabdar@Sun.COM 
13717917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
13727917SReza.Sabdar@Sun.COM 
13737917SReza.Sabdar@Sun.COM 	tape_open_send_reply(connection, NDMP_NO_ERR);
13747917SReza.Sabdar@Sun.COM }
13757917SReza.Sabdar@Sun.COM 
13767917SReza.Sabdar@Sun.COM 
13777917SReza.Sabdar@Sun.COM /*
13787917SReza.Sabdar@Sun.COM  * common_tape_close
13797917SReza.Sabdar@Sun.COM  *
13807917SReza.Sabdar@Sun.COM  * Generic function for closing the tape
13817917SReza.Sabdar@Sun.COM  *
13827917SReza.Sabdar@Sun.COM  * Parameters:
13837917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
13847917SReza.Sabdar@Sun.COM  *
13857917SReza.Sabdar@Sun.COM  * Returns:
13867917SReza.Sabdar@Sun.COM  *   void
13877917SReza.Sabdar@Sun.COM  */
13887917SReza.Sabdar@Sun.COM static void
common_tape_close(ndmp_connection_t * connection)13897917SReza.Sabdar@Sun.COM common_tape_close(ndmp_connection_t *connection)
13907917SReza.Sabdar@Sun.COM {
13917917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
13927917SReza.Sabdar@Sun.COM 	ndmp_tape_close_reply reply;
13937917SReza.Sabdar@Sun.COM 
13947917SReza.Sabdar@Sun.COM 	(void) ndmp_open_list_del(session->ns_tape.td_adapter_name,
13957917SReza.Sabdar@Sun.COM 	    session->ns_tape.td_sid, session->ns_tape.td_lun);
13967917SReza.Sabdar@Sun.COM 	(void) close(session->ns_tape.td_fd);
13977917SReza.Sabdar@Sun.COM 	session->ns_tape.td_fd = -1;
13987917SReza.Sabdar@Sun.COM 	session->ns_tape.td_sid = 0;
13997917SReza.Sabdar@Sun.COM 	session->ns_tape.td_lun = 0;
14007917SReza.Sabdar@Sun.COM 	session->ns_tape.td_write = 0;
14017917SReza.Sabdar@Sun.COM 	(void) memset(session->ns_tape.td_adapter_name, 0,
14027917SReza.Sabdar@Sun.COM 	    sizeof (session->ns_tape.td_adapter_name));
14037917SReza.Sabdar@Sun.COM 	session->ns_tape.td_record_count = 0;
14047917SReza.Sabdar@Sun.COM 	session->ns_tape.td_eom_seen = FALSE;
14057917SReza.Sabdar@Sun.COM 
14067917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
14077917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
14087917SReza.Sabdar@Sun.COM 	    "sending tape_close reply");
14097917SReza.Sabdar@Sun.COM }
14107917SReza.Sabdar@Sun.COM 
14117917SReza.Sabdar@Sun.COM /*
14127917SReza.Sabdar@Sun.COM  * tape_open
14137917SReza.Sabdar@Sun.COM  *
14147917SReza.Sabdar@Sun.COM  * Will try to open the tape with the given flags and
14157917SReza.Sabdar@Sun.COM  * path using the given retries and delay intervals
14167917SReza.Sabdar@Sun.COM  */
14177917SReza.Sabdar@Sun.COM int
tape_open(char * path,int flags)14187917SReza.Sabdar@Sun.COM tape_open(char *path, int flags)
14197917SReza.Sabdar@Sun.COM {
14207917SReza.Sabdar@Sun.COM 	int fd;
14217917SReza.Sabdar@Sun.COM 	int i = 0;
14227917SReza.Sabdar@Sun.COM 
14237917SReza.Sabdar@Sun.COM 	while ((fd = open(path, flags)) == -1 &&
14247917SReza.Sabdar@Sun.COM 	    i++ < ndmp_tape_open_retries) {
14257917SReza.Sabdar@Sun.COM 		if (errno != EBUSY)
14267917SReza.Sabdar@Sun.COM 			break;
14277917SReza.Sabdar@Sun.COM 		(void) usleep(ndmp_tape_open_delay);
14287917SReza.Sabdar@Sun.COM 	}
14297917SReza.Sabdar@Sun.COM 	return (fd);
14307917SReza.Sabdar@Sun.COM }
1431