12654012fSReza Sabdar /*
286c48bbfSReza Sabdar * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
32654012fSReza Sabdar * Use is subject to license terms.
42654012fSReza Sabdar */
52654012fSReza Sabdar /*
62654012fSReza Sabdar * BSD 3 Clause License
72654012fSReza Sabdar *
82654012fSReza Sabdar * Copyright (c) 2007, The Storage Networking Industry Association.
92654012fSReza Sabdar *
102654012fSReza Sabdar * Redistribution and use in source and binary forms, with or without
112654012fSReza Sabdar * modification, are permitted provided that the following conditions
122654012fSReza Sabdar * are met:
132654012fSReza Sabdar * - Redistributions of source code must retain the above copyright
142654012fSReza Sabdar * notice, this list of conditions and the following disclaimer.
152654012fSReza Sabdar *
162654012fSReza Sabdar * - Redistributions in binary form must reproduce the above copyright
172654012fSReza Sabdar * notice, this list of conditions and the following disclaimer in
182654012fSReza Sabdar * the documentation and/or other materials provided with the
192654012fSReza Sabdar * distribution.
202654012fSReza Sabdar *
212654012fSReza Sabdar * - Neither the name of The Storage Networking Industry Association (SNIA)
222654012fSReza Sabdar * nor the names of its contributors may be used to endorse or promote
232654012fSReza Sabdar * products derived from this software without specific prior written
242654012fSReza Sabdar * permission.
252654012fSReza Sabdar *
262654012fSReza Sabdar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
272654012fSReza Sabdar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
282654012fSReza Sabdar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
292654012fSReza Sabdar * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
302654012fSReza Sabdar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
312654012fSReza Sabdar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
322654012fSReza Sabdar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
332654012fSReza Sabdar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
342654012fSReza Sabdar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
352654012fSReza Sabdar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
362654012fSReza Sabdar * POSSIBILITY OF SUCH DAMAGE.
372654012fSReza Sabdar */
382654012fSReza Sabdar /* Copyright (c) 2007, The Storage Networking Industry Association. */
392654012fSReza Sabdar /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40*9ee94b97SJan Kryl /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
412654012fSReza Sabdar
422654012fSReza Sabdar #include <sys/param.h>
432654012fSReza Sabdar #include <fcntl.h>
442654012fSReza Sabdar #include <sys/mtio.h>
452654012fSReza Sabdar #include <errno.h>
462654012fSReza Sabdar #include <stdio.h>
472654012fSReza Sabdar #include <string.h>
482654012fSReza Sabdar #include <unistd.h>
492654012fSReza Sabdar #include "ndmpd_common.h"
502654012fSReza Sabdar #include "ndmpd.h"
512654012fSReza Sabdar
522654012fSReza Sabdar static void tape_open_send_reply(ndmp_connection_t *connection, int err);
532654012fSReza Sabdar static void unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
542654012fSReza Sabdar ndmp_tape_read_reply *reply);
552654012fSReza Sabdar static boolean_t validmode(int mode);
562654012fSReza Sabdar static void common_tape_open(ndmp_connection_t *connection, char *devname,
572654012fSReza Sabdar int ndmpmode);
582654012fSReza Sabdar static void common_tape_close(ndmp_connection_t *connection);
592654012fSReza Sabdar
602654012fSReza Sabdar /*
612654012fSReza Sabdar * Configurable delay & time when the tape is
622654012fSReza Sabdar * busy during opening the tape.
632654012fSReza Sabdar */
642654012fSReza Sabdar int ndmp_tape_open_retries = 5;
652654012fSReza Sabdar int ndmp_tape_open_delay = 1000;
662654012fSReza Sabdar
672654012fSReza Sabdar /*
68*9ee94b97SJan Kryl * A few words about EOT (end-of-tape) and EOM handling on tapes with SVR4
69*9ee94b97SJan Kryl * semantic:
70*9ee94b97SJan Kryl *
71*9ee94b97SJan Kryl * We adhere to terminology as used in st driver. EOT means end of recorded
72*9ee94b97SJan Kryl * data on a tape. This is different from EOM (somewhere referred to as LEOT)
73*9ee94b97SJan Kryl * which is the end of tape medium. EOT is meaningful only for reads while EOM
74*9ee94b97SJan Kryl * is meaningful only for writes. It's not possible to read after EOT (fails
75*9ee94b97SJan Kryl * with EIO), but it's possible to write data after EOM. EOM returned by st
76*9ee94b97SJan Kryl * driver on modern tape drives is just indication that the physical end of
77*9ee94b97SJan Kryl * tape medium is nearing and that writer should write just the necessary
78*9ee94b97SJan Kryl * minimum and stop writing. When physical end of tape is reached all writes
79*9ee94b97SJan Kryl * return EIO. If EOM is crossed during read operation then st driver doesn't
80*9ee94b97SJan Kryl * bother to report it to client and that's alright because reads don't care
81*9ee94b97SJan Kryl * where medium physically ends but they care about meaningful data recorded on
82*9ee94b97SJan Kryl * the tape and as long as there are such data reads should continue to work.
83*9ee94b97SJan Kryl *
84*9ee94b97SJan Kryl * When reading EOT is signalled by st driver by two empty consecutive reads
85*9ee94b97SJan Kryl * (with FSF done between them). When writing EOM is signalled by empty write
86*9ee94b97SJan Kryl * (a write which writes zero bytes). Following writes succeed until physical
87*9ee94b97SJan Kryl * end of tape is reached in which case EIO is returned.
88*9ee94b97SJan Kryl */
89*9ee94b97SJan Kryl
90*9ee94b97SJan Kryl /*
912654012fSReza Sabdar * ************************************************************************
922654012fSReza Sabdar * NDMP V2 HANDLERS
932654012fSReza Sabdar * ************************************************************************
942654012fSReza Sabdar */
952654012fSReza Sabdar
962654012fSReza Sabdar /*
972654012fSReza Sabdar * ndmpd_tape_open_v2
982654012fSReza Sabdar *
992654012fSReza Sabdar * This handler opens the specified tape device.
1002654012fSReza Sabdar *
1012654012fSReza Sabdar * Parameters:
1022654012fSReza Sabdar * connection (input) - connection handle.
1032654012fSReza Sabdar * body (input) - request message body.
1042654012fSReza Sabdar *
1052654012fSReza Sabdar * Returns:
1062654012fSReza Sabdar * void
1072654012fSReza Sabdar */
1082654012fSReza Sabdar void
ndmpd_tape_open_v2(ndmp_connection_t * connection,void * body)1092654012fSReza Sabdar ndmpd_tape_open_v2(ndmp_connection_t *connection, void *body)
1102654012fSReza Sabdar {
1112654012fSReza Sabdar ndmp_tape_open_request_v2 *request = (ndmp_tape_open_request_v2 *) body;
1122654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
1132654012fSReza Sabdar char adptnm[SCSI_MAX_NAME];
1142654012fSReza Sabdar int mode;
1152654012fSReza Sabdar int sid, lun;
1162654012fSReza Sabdar int err;
1172654012fSReza Sabdar scsi_adapter_t *sa;
1182654012fSReza Sabdar int devid;
1192654012fSReza Sabdar
1202654012fSReza Sabdar err = NDMP_NO_ERR;
1212654012fSReza Sabdar
1222654012fSReza Sabdar if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
1232654012fSReza Sabdar NDMP_LOG(LOG_INFO,
1242654012fSReza Sabdar "Connection already has a tape or scsi device open");
1252654012fSReza Sabdar err = NDMP_DEVICE_OPENED_ERR;
1262654012fSReza Sabdar } else if (request->mode != NDMP_TAPE_READ_MODE &&
1272654012fSReza Sabdar request->mode != NDMP_TAPE_WRITE_MODE &&
1282654012fSReza Sabdar request->mode != NDMP_TAPE_RAW1_MODE) {
1292654012fSReza Sabdar err = NDMP_ILLEGAL_ARGS_ERR;
1302654012fSReza Sabdar }
1312654012fSReza Sabdar
1322654012fSReza Sabdar if ((sa = scsi_get_adapter(0)) != NULL) {
1332654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
1342654012fSReza Sabdar "Adapter device opened: %s", request->device.name);
1352654012fSReza Sabdar (void) strlcpy(adptnm, request->device.name, SCSI_MAX_NAME-2);
1362654012fSReza Sabdar adptnm[SCSI_MAX_NAME-1] = '\0';
1372654012fSReza Sabdar sid = lun = -1;
1382654012fSReza Sabdar }
1392654012fSReza Sabdar /* try to get the scsi id etc.... */
1402654012fSReza Sabdar if (sa) {
1412654012fSReza Sabdar scsi_find_sid_lun(sa, request->device.name, &sid, &lun);
1422654012fSReza Sabdar if (ndmp_open_list_find(request->device.name, sid, lun) == 0 &&
1432654012fSReza Sabdar (devid = tape_open(request->device.name,
1442654012fSReza Sabdar O_RDWR | O_NDELAY)) < 0) {
1452654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Failed to open device %s: %m.",
1462654012fSReza Sabdar request->device.name);
1472654012fSReza Sabdar err = NDMP_NO_DEVICE_ERR;
1482654012fSReza Sabdar }
1492654012fSReza Sabdar else
1502654012fSReza Sabdar (void) close(devid);
1512654012fSReza Sabdar } else {
1522654012fSReza Sabdar NDMP_LOG(LOG_ERR, "%s: No such tape device.",
1532654012fSReza Sabdar request->device.name);
1542654012fSReza Sabdar err = NDMP_NO_DEVICE_ERR;
1552654012fSReza Sabdar }
1562654012fSReza Sabdar if (err != NDMP_NO_ERR) {
1572654012fSReza Sabdar tape_open_send_reply(connection, err);
1582654012fSReza Sabdar return;
1592654012fSReza Sabdar }
1602654012fSReza Sabdar
1612654012fSReza Sabdar switch (ndmp_open_list_add(connection, adptnm, sid, lun, devid)) {
1622654012fSReza Sabdar case 0:
1632654012fSReza Sabdar err = NDMP_NO_ERR;
1642654012fSReza Sabdar break;
1652654012fSReza Sabdar case EBUSY:
1662654012fSReza Sabdar err = NDMP_DEVICE_BUSY_ERR;
1672654012fSReza Sabdar break;
1682654012fSReza Sabdar case ENOMEM:
1692654012fSReza Sabdar err = NDMP_NO_MEM_ERR;
1702654012fSReza Sabdar break;
1712654012fSReza Sabdar default:
1722654012fSReza Sabdar err = NDMP_IO_ERR;
1732654012fSReza Sabdar }
1742654012fSReza Sabdar if (err != NDMP_NO_ERR) {
1752654012fSReza Sabdar tape_open_send_reply(connection, err);
1762654012fSReza Sabdar return;
1772654012fSReza Sabdar }
1782654012fSReza Sabdar
1792654012fSReza Sabdar /*
1802654012fSReza Sabdar * According to Connectathon 2001, the 0x7fffffff is a secret
1812654012fSReza Sabdar * code between "Workstartion Solutions" and * net_app.
1822654012fSReza Sabdar * If mode is set to this value, tape_open() won't fail if
1832654012fSReza Sabdar * the tape device is not ready.
1842654012fSReza Sabdar */
1852654012fSReza Sabdar if (request->mode != NDMP_TAPE_RAW1_MODE &&
1862654012fSReza Sabdar !is_tape_unit_ready(adptnm, 0)) {
1872654012fSReza Sabdar (void) ndmp_open_list_del(adptnm, sid, lun);
1882654012fSReza Sabdar tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
1892654012fSReza Sabdar return;
1902654012fSReza Sabdar }
1912654012fSReza Sabdar
1922654012fSReza Sabdar mode = (request->mode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
1932654012fSReza Sabdar mode |= O_NDELAY;
1942654012fSReza Sabdar if ((session->ns_tape.td_fd = open(request->device.name, mode)) < 0) {
1952654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
1962654012fSReza Sabdar request->device.name);
1972654012fSReza Sabdar switch (errno) {
1982654012fSReza Sabdar case EACCES:
1992654012fSReza Sabdar err = NDMP_WRITE_PROTECT_ERR;
2002654012fSReza Sabdar break;
2012654012fSReza Sabdar case ENXIO:
2022654012fSReza Sabdar case ENOENT:
2032654012fSReza Sabdar err = NDMP_NO_DEVICE_ERR;
2042654012fSReza Sabdar break;
2052654012fSReza Sabdar case EBUSY:
2062654012fSReza Sabdar err = NDMP_DEVICE_BUSY_ERR;
2072654012fSReza Sabdar break;
2082654012fSReza Sabdar default:
2092654012fSReza Sabdar err = NDMP_IO_ERR;
2102654012fSReza Sabdar }
2112654012fSReza Sabdar
2122654012fSReza Sabdar (void) ndmp_open_list_del(adptnm, sid, lun);
2132654012fSReza Sabdar tape_open_send_reply(connection, err);
2142654012fSReza Sabdar return;
2152654012fSReza Sabdar }
2162654012fSReza Sabdar
2172654012fSReza Sabdar session->ns_tape.td_mode = request->mode;
2182654012fSReza Sabdar session->ns_tape.td_sid = sid;
2192654012fSReza Sabdar session->ns_tape.td_lun = lun;
2202654012fSReza Sabdar (void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
2212654012fSReza Sabdar session->ns_tape.td_record_count = 0;
2222654012fSReza Sabdar
2232654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
2242654012fSReza Sabdar
2252654012fSReza Sabdar tape_open_send_reply(connection, NDMP_NO_ERR);
2262654012fSReza Sabdar }
2272654012fSReza Sabdar
2282654012fSReza Sabdar
2292654012fSReza Sabdar /*
2302654012fSReza Sabdar * ndmpd_tape_close_v2
2312654012fSReza Sabdar *
2322654012fSReza Sabdar * This handler closes the currently open tape device.
2332654012fSReza Sabdar *
2342654012fSReza Sabdar * Parameters:
2352654012fSReza Sabdar * connection (input) - connection handle.
2362654012fSReza Sabdar * body (input) - request message body.
2372654012fSReza Sabdar *
2382654012fSReza Sabdar * Returns:
2392654012fSReza Sabdar * void
2402654012fSReza Sabdar */
2412654012fSReza Sabdar /*ARGSUSED*/
2422654012fSReza Sabdar void
ndmpd_tape_close_v2(ndmp_connection_t * connection,void * body)2432654012fSReza Sabdar ndmpd_tape_close_v2(ndmp_connection_t *connection, void *body)
2442654012fSReza Sabdar {
2452654012fSReza Sabdar ndmp_tape_close_reply reply;
2462654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
2472654012fSReza Sabdar
2482654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
2492654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
2502654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
2512654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
2522654012fSReza Sabdar "sending tape_close reply");
2532654012fSReza Sabdar return;
2542654012fSReza Sabdar }
2552654012fSReza Sabdar common_tape_close(connection);
2562654012fSReza Sabdar
2572654012fSReza Sabdar }
2582654012fSReza Sabdar
2592654012fSReza Sabdar /*
2602654012fSReza Sabdar * ndmpd_tape_get_state_v2
2612654012fSReza Sabdar *
2622654012fSReza Sabdar * This handler handles the tape_get_state request.
2632654012fSReza Sabdar * Status information for the currently open tape device is returned.
2642654012fSReza Sabdar *
2652654012fSReza Sabdar * Parameters:
2662654012fSReza Sabdar * connection (input) - connection handle.
2672654012fSReza Sabdar * body (input) - request message body.
2682654012fSReza Sabdar *
2692654012fSReza Sabdar * Returns:
2702654012fSReza Sabdar * void
2712654012fSReza Sabdar */
2722654012fSReza Sabdar /*ARGSUSED*/
2732654012fSReza Sabdar void
ndmpd_tape_get_state_v2(ndmp_connection_t * connection,void * body)2742654012fSReza Sabdar ndmpd_tape_get_state_v2(ndmp_connection_t *connection, void *body)
2752654012fSReza Sabdar
2762654012fSReza Sabdar {
2772654012fSReza Sabdar ndmp_tape_get_state_reply_v2 reply;
2782654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
2792654012fSReza Sabdar struct mtget mtstatus;
2802654012fSReza Sabdar struct mtdrivetype_request dtpr;
2812654012fSReza Sabdar struct mtdrivetype dtp;
2822654012fSReza Sabdar
2832654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
2842654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
2852654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
2862654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
2872654012fSReza Sabdar "sending tape_get_state reply");
2882654012fSReza Sabdar return;
2892654012fSReza Sabdar }
2902654012fSReza Sabdar
2912654012fSReza Sabdar if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) < 0) {
2922654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Failed to get status from tape: %m.");
2932654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
2942654012fSReza Sabdar reply.error = NDMP_IO_ERR;
2952654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
2962654012fSReza Sabdar "sending tape_get_state reply");
2972654012fSReza Sabdar return;
2982654012fSReza Sabdar }
2992654012fSReza Sabdar
3002654012fSReza Sabdar dtpr.size = sizeof (struct mtdrivetype);
3012654012fSReza Sabdar dtpr.mtdtp = &dtp;
3022654012fSReza Sabdar if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
3032654012fSReza Sabdar NDMP_LOG(LOG_ERR,
3042654012fSReza Sabdar "Failed to get drive type information from tape: %m.");
3052654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
3062654012fSReza Sabdar reply.error = NDMP_IO_ERR;
3072654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
3082654012fSReza Sabdar "sending tape_get_state reply");
3092654012fSReza Sabdar return;
3102654012fSReza Sabdar }
3112654012fSReza Sabdar
3122654012fSReza Sabdar reply.flags = 0;
3132654012fSReza Sabdar
3142654012fSReza Sabdar reply.file_num = mtstatus.mt_fileno;
3152654012fSReza Sabdar reply.soft_errors = 0;
3162654012fSReza Sabdar reply.block_size = dtp.bsize;
3172654012fSReza Sabdar if (dtp.bsize == 0)
3182654012fSReza Sabdar reply.blockno = mtstatus.mt_blkno;
3192654012fSReza Sabdar else
3202654012fSReza Sabdar reply.blockno = mtstatus.mt_blkno *
3212654012fSReza Sabdar (session->ns_mover.md_record_size / dtp.bsize);
3222654012fSReza Sabdar
3232654012fSReza Sabdar reply.soft_errors = 0;
3242654012fSReza Sabdar reply.total_space = long_long_to_quad(0); /* not supported */
3252654012fSReza Sabdar reply.space_remain = long_long_to_quad(0); /* not supported */
3262654012fSReza Sabdar
3272654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
3282654012fSReza Sabdar "flags: 0x%x, file_num: %d, block_size: %d, blockno: %d",
3292654012fSReza Sabdar reply.flags, reply.file_num, reply.block_size, reply.blockno);
3302654012fSReza Sabdar
3312654012fSReza Sabdar reply.error = NDMP_NO_ERR;
3322654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
3332654012fSReza Sabdar "sending tape_get_state reply");
3342654012fSReza Sabdar }
3352654012fSReza Sabdar
3362654012fSReza Sabdar
3372654012fSReza Sabdar /*
3382654012fSReza Sabdar * ndmpd_tape_mtio_v2
3392654012fSReza Sabdar *
3402654012fSReza Sabdar * This handler handles tape_mtio requests.
3412654012fSReza Sabdar *
3422654012fSReza Sabdar * Parameters:
3432654012fSReza Sabdar * connection (input) - connection handle.
3442654012fSReza Sabdar * body (input) - request message body.
3452654012fSReza Sabdar *
3462654012fSReza Sabdar * Returns:
3472654012fSReza Sabdar * void
3482654012fSReza Sabdar */
3492654012fSReza Sabdar void
ndmpd_tape_mtio_v2(ndmp_connection_t * connection,void * body)3502654012fSReza Sabdar ndmpd_tape_mtio_v2(ndmp_connection_t *connection, void *body)
3512654012fSReza Sabdar {
3522654012fSReza Sabdar ndmp_tape_mtio_request *request = (ndmp_tape_mtio_request *) body;
3532654012fSReza Sabdar ndmp_tape_mtio_reply reply;
3542654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
3552654012fSReza Sabdar
3562654012fSReza Sabdar struct mtop tapeop;
3572654012fSReza Sabdar struct mtget mtstatus;
3582654012fSReza Sabdar int retry = 0;
3592654012fSReza Sabdar int rc;
3602654012fSReza Sabdar
3612654012fSReza Sabdar reply.resid_count = 0;
3622654012fSReza Sabdar
3632654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
3642654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
3652654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
3662654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
3672654012fSReza Sabdar "sending tape_mtio reply");
3682654012fSReza Sabdar return;
3692654012fSReza Sabdar }
3702654012fSReza Sabdar
3712654012fSReza Sabdar reply.error = NDMP_NO_ERR;
3722654012fSReza Sabdar switch (request->tape_op) {
3732654012fSReza Sabdar case NDMP_MTIO_FSF:
3742654012fSReza Sabdar tapeop.mt_op = MTFSF;
3752654012fSReza Sabdar break;
3762654012fSReza Sabdar case NDMP_MTIO_BSF:
3772654012fSReza Sabdar tapeop.mt_op = MTBSF;
3782654012fSReza Sabdar break;
3792654012fSReza Sabdar case NDMP_MTIO_FSR:
3802654012fSReza Sabdar tapeop.mt_op = MTFSR;
3812654012fSReza Sabdar break;
3822654012fSReza Sabdar case NDMP_MTIO_BSR:
3832654012fSReza Sabdar tapeop.mt_op = MTBSR;
3842654012fSReza Sabdar break;
3852654012fSReza Sabdar case NDMP_MTIO_REW:
3862654012fSReza Sabdar tapeop.mt_op = MTREW;
3872654012fSReza Sabdar break;
3882654012fSReza Sabdar case NDMP_MTIO_EOF:
3892654012fSReza Sabdar if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE)
3902654012fSReza Sabdar reply.error = NDMP_PERMISSION_ERR;
3912654012fSReza Sabdar tapeop.mt_op = MTWEOF;
3922654012fSReza Sabdar break;
3932654012fSReza Sabdar case NDMP_MTIO_OFF:
3942654012fSReza Sabdar tapeop.mt_op = MTOFFL;
3952654012fSReza Sabdar break;
3962654012fSReza Sabdar
3972654012fSReza Sabdar case NDMP_MTIO_TUR: /* test unit ready */
3982654012fSReza Sabdar
3992654012fSReza Sabdar if (is_tape_unit_ready(session->ns_tape.td_adapter_name,
4002654012fSReza Sabdar session->ns_tape.td_fd) == 0)
4012654012fSReza Sabdar /* tape not ready ? */
4022654012fSReza Sabdar reply.error = NDMP_NO_TAPE_LOADED_ERR;
4032654012fSReza Sabdar break;
4042654012fSReza Sabdar
4052654012fSReza Sabdar default:
4062654012fSReza Sabdar reply.error = NDMP_ILLEGAL_ARGS_ERR;
4072654012fSReza Sabdar }
4082654012fSReza Sabdar
4092654012fSReza Sabdar if (reply.error == NDMP_NO_ERR && request->tape_op != NDMP_MTIO_TUR) {
4102654012fSReza Sabdar tapeop.mt_count = request->count;
4112654012fSReza Sabdar
4122654012fSReza Sabdar do {
4132654012fSReza Sabdar NS_UPD(twait, trun);
414*9ee94b97SJan Kryl errno = 0;
4152654012fSReza Sabdar rc = ioctl(session->ns_tape.td_fd, MTIOCTOP, &tapeop);
4162654012fSReza Sabdar NS_UPD(trun, twait);
4172654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
4182654012fSReza Sabdar "ioctl MTIO rc:%d, cmd:%d, retry:%d, error: %d",
4192654012fSReza Sabdar rc, tapeop.mt_op, retry, errno);
4202654012fSReza Sabdar } while (rc < 0 && errno == EIO &&
4212654012fSReza Sabdar retry++ < 5);
4222654012fSReza Sabdar
4232654012fSReza Sabdar /*
4242654012fSReza Sabdar * Ignore I/O errors since these usually are the result of
4252654012fSReza Sabdar * attempting to position past the beginning or end of the tape.
4262654012fSReza Sabdar * The residual count will be returned and can be used to
4272654012fSReza Sabdar * determine that the call was not completely successful.
4282654012fSReza Sabdar */
4292654012fSReza Sabdar if (rc < 0) {
4302654012fSReza Sabdar NDMP_LOG(LOG_ERR,
4312654012fSReza Sabdar "Failed to send command to tape: %m.");
4322654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCTOP) error: %m.");
4332654012fSReza Sabdar
4342654012fSReza Sabdar /* MTWEOF doesnt have residual count */
4352654012fSReza Sabdar if (tapeop.mt_op == MTWEOF)
4362654012fSReza Sabdar reply.error = NDMP_IO_ERR;
4372654012fSReza Sabdar else
4382654012fSReza Sabdar reply.error = NDMP_NO_ERR;
4392654012fSReza Sabdar reply.resid_count = tapeop.mt_count;
4402654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
4412654012fSReza Sabdar "sending tape_mtio reply");
4422654012fSReza Sabdar return;
4432654012fSReza Sabdar }
4442654012fSReza Sabdar
4452654012fSReza Sabdar if (request->tape_op != NDMP_MTIO_REW &&
4462654012fSReza Sabdar request->tape_op != NDMP_MTIO_OFF) {
4472654012fSReza Sabdar if (ioctl(session->ns_tape.td_fd, MTIOCGET,
4482654012fSReza Sabdar &mtstatus) < 0) {
4492654012fSReza Sabdar NDMP_LOG(LOG_ERR,
4502654012fSReza Sabdar "Failed to send command to tape: %m.");
4512654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
4522654012fSReza Sabdar "ioctl(MTIOCGET) error: %m.");
4532654012fSReza Sabdar reply.error = NDMP_IO_ERR;
4542654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
4552654012fSReza Sabdar "sending tape_mtio reply");
4562654012fSReza Sabdar
4572654012fSReza Sabdar return;
4582654012fSReza Sabdar }
4592654012fSReza Sabdar
4602654012fSReza Sabdar reply.resid_count = labs(mtstatus.mt_resid);
4612654012fSReza Sabdar }
4622654012fSReza Sabdar }
4632654012fSReza Sabdar
4642654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "resid_count: %d",
4652654012fSReza Sabdar reply.resid_count);
4662654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply, "sending tape_mtio reply");
4672654012fSReza Sabdar }
4682654012fSReza Sabdar
4692654012fSReza Sabdar
4702654012fSReza Sabdar /*
4712654012fSReza Sabdar * ndmpd_tape_read_v2
4722654012fSReza Sabdar *
4732654012fSReza Sabdar * This handler handles tape_read requests.
4742654012fSReza Sabdar * This interface is a non-buffered interface. Each read request
4752654012fSReza Sabdar * maps directly to a read to the tape device. It is the responsibility
4762654012fSReza Sabdar * of the NDMP client to issue read requests with a length that is at
4772654012fSReza Sabdar * least as large as the record size used write the tape. The tape driver
4782654012fSReza Sabdar * always reads a full record. Data is discarded if the read request is
4792654012fSReza Sabdar * smaller than the record size.
4802654012fSReza Sabdar * It is the responsibility of the NDMP client to ensure that the
4812654012fSReza Sabdar * length is a multiple of the tape block size if the tape device
4822654012fSReza Sabdar * is in fixed block mode.
4832654012fSReza Sabdar *
4842654012fSReza Sabdar * Parameters:
4852654012fSReza Sabdar * connection (input) - connection handle.
4862654012fSReza Sabdar * body (input) - request message body.
4872654012fSReza Sabdar *
4882654012fSReza Sabdar * Returns:
4892654012fSReza Sabdar * void
4902654012fSReza Sabdar */
4912654012fSReza Sabdar void
ndmpd_tape_read_v2(ndmp_connection_t * connection,void * body)4922654012fSReza Sabdar ndmpd_tape_read_v2(ndmp_connection_t *connection, void *body)
4932654012fSReza Sabdar {
4942654012fSReza Sabdar ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
4952654012fSReza Sabdar ndmp_tape_read_reply reply;
4962654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
4972654012fSReza Sabdar char *buf;
4982654012fSReza Sabdar
4992654012fSReza Sabdar reply.data_in.data_in_len = 0;
5002654012fSReza Sabdar
5012654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
5022654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
5032654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
5042654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
5052654012fSReza Sabdar "sending tape_read reply");
5062654012fSReza Sabdar return;
5072654012fSReza Sabdar }
5082654012fSReza Sabdar if (request->count == 0) {
5092654012fSReza Sabdar reply.error = NDMP_NO_ERR;
5102654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
5112654012fSReza Sabdar "sending tape_read reply");
5122654012fSReza Sabdar return;
5132654012fSReza Sabdar }
5142654012fSReza Sabdar if ((buf = ndmp_malloc(request->count)) == 0) {
5152654012fSReza Sabdar reply.error = NDMP_NO_MEM_ERR;
5162654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
5172654012fSReza Sabdar "sending tape_read reply");
5182654012fSReza Sabdar return;
5192654012fSReza Sabdar }
5202654012fSReza Sabdar
5212654012fSReza Sabdar unbuffered_read(session, buf, request->count, &reply);
5222654012fSReza Sabdar
5232654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
5242654012fSReza Sabdar (void) free(buf);
5252654012fSReza Sabdar }
5262654012fSReza Sabdar
5272654012fSReza Sabdar
5282654012fSReza Sabdar /*
5292654012fSReza Sabdar * ndmpd_tape_execute_cdb_v2
5302654012fSReza Sabdar *
5312654012fSReza Sabdar * This handler handles tape_execute_cdb requests.
5322654012fSReza Sabdar *
5332654012fSReza Sabdar * Parameters:
5342654012fSReza Sabdar * connection (input) - connection handle.
5352654012fSReza Sabdar * body (input) - request message body.
5362654012fSReza Sabdar *
5372654012fSReza Sabdar * Returns:
5382654012fSReza Sabdar * void
5392654012fSReza Sabdar */
5402654012fSReza Sabdar void
ndmpd_tape_execute_cdb_v2(ndmp_connection_t * connection,void * body)5412654012fSReza Sabdar ndmpd_tape_execute_cdb_v2(ndmp_connection_t *connection, void *body)
5422654012fSReza Sabdar {
5432654012fSReza Sabdar ndmp_tape_execute_cdb_request *request;
5442654012fSReza Sabdar ndmp_tape_execute_cdb_reply reply;
5452654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
5462654012fSReza Sabdar
5472654012fSReza Sabdar request = (ndmp_tape_execute_cdb_request *) body;
5482654012fSReza Sabdar
5492654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
5502654012fSReza Sabdar (void) memset((void *) &reply, 0, sizeof (reply));
5512654012fSReza Sabdar
5522654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
5532654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
5542654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
5552654012fSReza Sabdar "sending tape_execute_cdb reply");
5562654012fSReza Sabdar } else {
5572654012fSReza Sabdar ndmp_execute_cdb(session, session->ns_tape.td_adapter_name,
5582654012fSReza Sabdar session->ns_tape.td_sid, session->ns_tape.td_lun,
5592654012fSReza Sabdar (ndmp_execute_cdb_request *)request);
5602654012fSReza Sabdar }
5612654012fSReza Sabdar }
5622654012fSReza Sabdar
5632654012fSReza Sabdar
5642654012fSReza Sabdar /*
5652654012fSReza Sabdar * ************************************************************************
5662654012fSReza Sabdar * NDMP V3 HANDLERS
5672654012fSReza Sabdar * ************************************************************************
5682654012fSReza Sabdar */
5692654012fSReza Sabdar
5702654012fSReza Sabdar /*
5712654012fSReza Sabdar * ndmpd_tape_open_v3
5722654012fSReza Sabdar *
5732654012fSReza Sabdar * This handler opens the specified tape device.
5742654012fSReza Sabdar *
5752654012fSReza Sabdar * Parameters:
5762654012fSReza Sabdar * connection (input) - connection handle.
5772654012fSReza Sabdar * body (input) - request message body.
5782654012fSReza Sabdar *
5792654012fSReza Sabdar * Returns:
5802654012fSReza Sabdar * void
5812654012fSReza Sabdar */
5822654012fSReza Sabdar void
ndmpd_tape_open_v3(ndmp_connection_t * connection,void * body)5832654012fSReza Sabdar ndmpd_tape_open_v3(ndmp_connection_t *connection, void *body)
5842654012fSReza Sabdar {
5852654012fSReza Sabdar ndmp_tape_open_request_v3 *request = (ndmp_tape_open_request_v3 *)body;
5862654012fSReza Sabdar
5872654012fSReza Sabdar common_tape_open(connection, request->device, request->mode);
5882654012fSReza Sabdar }
5892654012fSReza Sabdar
5902654012fSReza Sabdar
5912654012fSReza Sabdar /*
5922654012fSReza Sabdar * ndmpd_tape_get_state_v3
5932654012fSReza Sabdar *
5942654012fSReza Sabdar * This handler handles the ndmp_tape_get_state_request.
5952654012fSReza Sabdar * Status information for the currently open tape device is returned.
5962654012fSReza Sabdar *
5972654012fSReza Sabdar * Parameters:
5982654012fSReza Sabdar * connection (input) - connection handle.
5992654012fSReza Sabdar * body (input) - request message body.
6002654012fSReza Sabdar *
6012654012fSReza Sabdar * Returns:
6022654012fSReza Sabdar * void
6032654012fSReza Sabdar */
6042654012fSReza Sabdar /*ARGSUSED*/
6052654012fSReza Sabdar void
ndmpd_tape_get_state_v3(ndmp_connection_t * connection,void * body)6062654012fSReza Sabdar ndmpd_tape_get_state_v3(ndmp_connection_t *connection, void *body)
6072654012fSReza Sabdar {
6082654012fSReza Sabdar ndmp_tape_get_state_reply_v3 reply;
6092654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
6102654012fSReza Sabdar struct mtdrivetype_request dtpr;
6112654012fSReza Sabdar struct mtdrivetype dtp;
6122654012fSReza Sabdar struct mtget mtstatus;
6132654012fSReza Sabdar
6142654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
6152654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
6162654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
6172654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
6182654012fSReza Sabdar "sending tape_get_state reply");
6192654012fSReza Sabdar return;
6202654012fSReza Sabdar }
6212654012fSReza Sabdar
6222654012fSReza Sabdar if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
6232654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Failed to get status from tape: %m.");
6242654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
6252654012fSReza Sabdar
6262654012fSReza Sabdar reply.error = NDMP_IO_ERR;
6272654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
6282654012fSReza Sabdar "sending tape_get_state reply");
6292654012fSReza Sabdar return;
6302654012fSReza Sabdar }
6312654012fSReza Sabdar
6322654012fSReza Sabdar dtpr.size = sizeof (struct mtdrivetype);
6332654012fSReza Sabdar dtpr.mtdtp = &dtp;
6342654012fSReza Sabdar if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
6352654012fSReza Sabdar NDMP_LOG(LOG_ERR,
6362654012fSReza Sabdar "Failed to get drive type information from tape: %m.");
6372654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
6382654012fSReza Sabdar
6392654012fSReza Sabdar reply.error = NDMP_IO_ERR;
6402654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
6412654012fSReza Sabdar "sending tape_get_state reply");
6422654012fSReza Sabdar return;
6432654012fSReza Sabdar }
6442654012fSReza Sabdar
6452654012fSReza Sabdar reply.flags = 0;
6462654012fSReza Sabdar
6472654012fSReza Sabdar reply.file_num = mtstatus.mt_fileno;
6482654012fSReza Sabdar reply.soft_errors = 0;
6492654012fSReza Sabdar reply.block_size = dtp.bsize;
6502654012fSReza Sabdar if (dtp.bsize == 0)
6512654012fSReza Sabdar reply.blockno = mtstatus.mt_blkno;
6522654012fSReza Sabdar else
6532654012fSReza Sabdar reply.blockno = mtstatus.mt_blkno *
6542654012fSReza Sabdar (session->ns_mover.md_record_size / dtp.bsize);
6552654012fSReza Sabdar reply.total_space = long_long_to_quad(0); /* not supported */
6562654012fSReza Sabdar reply.space_remain = long_long_to_quad(0); /* not supported */
6572654012fSReza Sabdar reply.partition = 0; /* not supported */
6582654012fSReza Sabdar
6592654012fSReza Sabdar reply.soft_errors = 0;
6602654012fSReza Sabdar reply.total_space = long_long_to_quad(0LL);
6612654012fSReza Sabdar reply.space_remain = long_long_to_quad(0LL);
6622654012fSReza Sabdar
6632654012fSReza Sabdar reply.invalid = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
6642654012fSReza Sabdar NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
6652654012fSReza Sabdar NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
6662654012fSReza Sabdar NDMP_TAPE_STATE_PARTITION_INVALID;
6672654012fSReza Sabdar
6682654012fSReza Sabdar
6692654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "f 0x%x, fnum %d, bsize %d, bno: %d",
6702654012fSReza Sabdar reply.flags, reply.file_num, reply.block_size, reply.blockno);
6712654012fSReza Sabdar
6722654012fSReza Sabdar reply.error = NDMP_NO_ERR;
6732654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
6742654012fSReza Sabdar "sending tape_get_state reply");
6752654012fSReza Sabdar }
6762654012fSReza Sabdar
677*9ee94b97SJan Kryl /*
678*9ee94b97SJan Kryl * tape_is_at_bot
679*9ee94b97SJan Kryl *
680*9ee94b97SJan Kryl * Returns 1 if tape is at BOT, 0 on error or not at BOT.
681*9ee94b97SJan Kryl *
682*9ee94b97SJan Kryl */
683*9ee94b97SJan Kryl int
tape_is_at_bot(ndmpd_session_t * session)684*9ee94b97SJan Kryl tape_is_at_bot(ndmpd_session_t *session)
685*9ee94b97SJan Kryl {
686*9ee94b97SJan Kryl struct mtget mtstatus;
687*9ee94b97SJan Kryl
688*9ee94b97SJan Kryl if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == 0 &&
689*9ee94b97SJan Kryl mtstatus.mt_fileno == 0 && mtstatus.mt_blkno == 0)
690*9ee94b97SJan Kryl return (1);
691*9ee94b97SJan Kryl
692*9ee94b97SJan Kryl return (0);
693*9ee94b97SJan Kryl }
694*9ee94b97SJan Kryl
695*9ee94b97SJan Kryl /*
696*9ee94b97SJan Kryl * If we are at the beginning of a file (block # is zero) and read returns
697*9ee94b97SJan Kryl * zero bytes then this has to be end of recorded data on the tape. Repeated
698*9ee94b97SJan Kryl * reads at EOT return EIO. In both cases (zero read and EIO read) this
699*9ee94b97SJan Kryl * function should be used to test if we are at EOT.
700*9ee94b97SJan Kryl *
701*9ee94b97SJan Kryl * Returns 1 if tape is at BOF, 0 on error or not at BOF.
702*9ee94b97SJan Kryl */
703*9ee94b97SJan Kryl int
tape_is_at_bof(ndmpd_session_t * session)704*9ee94b97SJan Kryl tape_is_at_bof(ndmpd_session_t *session)
705*9ee94b97SJan Kryl {
706*9ee94b97SJan Kryl struct mtget mtstatus;
707*9ee94b97SJan Kryl
708*9ee94b97SJan Kryl if ((ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == 0) &&
709*9ee94b97SJan Kryl (mtstatus.mt_fileno > 0) && (mtstatus.mt_blkno == 0))
710*9ee94b97SJan Kryl return (1);
711*9ee94b97SJan Kryl
712*9ee94b97SJan Kryl return (0);
713*9ee94b97SJan Kryl }
714*9ee94b97SJan Kryl
715*9ee94b97SJan Kryl /*
716*9ee94b97SJan Kryl * Skips forward over a file mark and then back before the file mark. Why is
717*9ee94b97SJan Kryl * this needed? There are two reasons for it:
718*9ee94b97SJan Kryl *
719*9ee94b97SJan Kryl * 1) Because NDMPv4 spec requires that when EOF is encountered, the tape
720*9ee94b97SJan Kryl * position should remain on BOT side of the file mark. When st driver reaches
721*9ee94b97SJan Kryl * end of file get-position mtioctl reports position before file mark, however
722*9ee94b97SJan Kryl * the file mark has already been read and the real position is thus after the
723*9ee94b97SJan Kryl * file mark (real position as reported for example by uscsi commands). Thus we
724*9ee94b97SJan Kryl * need to do FSF, which does nothing but only updates file & block counter in
725*9ee94b97SJan Kryl * st driver and then BSF, which sets the position before the file mark. Thus
726*9ee94b97SJan Kryl * current position as reported by scsi and mtioctl will be in sync.
727*9ee94b97SJan Kryl *
728*9ee94b97SJan Kryl * 2) st driver returns EIO for repeated reads at EOF while according to NDMP
729*9ee94b97SJan Kryl * spec we should continue to return zero bytes until FSF is done. By skipping
730*9ee94b97SJan Kryl * forward and backward, st driver will return zero bytes for the next read
731*9ee94b97SJan Kryl * again and we don't need to specifically handle this case.
732*9ee94b97SJan Kryl */
733*9ee94b97SJan Kryl void
fm_dance(ndmpd_session_t * session)734*9ee94b97SJan Kryl fm_dance(ndmpd_session_t *session)
735*9ee94b97SJan Kryl {
736*9ee94b97SJan Kryl (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
737*9ee94b97SJan Kryl (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
738*9ee94b97SJan Kryl }
7392654012fSReza Sabdar
7402654012fSReza Sabdar /*
7412654012fSReza Sabdar * ndmpd_tape_write_v3
7422654012fSReza Sabdar *
743*9ee94b97SJan Kryl * This handler handles tape_write requests. This interface is a non-buffered
744*9ee94b97SJan Kryl * interface. Each write request maps directly to a write to the tape device.
745*9ee94b97SJan Kryl * It is the responsibility of the NDMP client to pad the data to the desired
746*9ee94b97SJan Kryl * record size. It is the responsibility of the NDMP client to ensure that the
747*9ee94b97SJan Kryl * length is a multiple of the tape block size if the tape device is in fixed
748*9ee94b97SJan Kryl * block mode.
749*9ee94b97SJan Kryl *
750*9ee94b97SJan Kryl * A logical end of tape will return number of bytes written less than
751*9ee94b97SJan Kryl * requested, and one more request to write will give 0 and NDMP_EOM_ERR,
752*9ee94b97SJan Kryl * followed by NDMP_NO_ERR until NDMP_IO_ERR when physical end of tape is
753*9ee94b97SJan Kryl * reached.
7542654012fSReza Sabdar *
7552654012fSReza Sabdar * Parameters:
7562654012fSReza Sabdar * connection (input) - connection handle.
7572654012fSReza Sabdar * body (input) - request message body.
7582654012fSReza Sabdar */
ndmpd_tape_write_v3(ndmp_connection_t * connection,void * body)759*9ee94b97SJan Kryl void ndmpd_tape_write_v3(ndmp_connection_t *connection, void *body) {
7602654012fSReza Sabdar ndmp_tape_write_request *request = (ndmp_tape_write_request *)body;
761*9ee94b97SJan Kryl ndmp_tape_write_reply reply; ndmpd_session_t *session =
762*9ee94b97SJan Kryl ndmp_get_client_data(connection); ssize_t n;
7632654012fSReza Sabdar
7642654012fSReza Sabdar reply.count = 0;
7652654012fSReza Sabdar
7662654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
7672654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
7682654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
7692654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
7702654012fSReza Sabdar "sending tape_write reply");
7712654012fSReza Sabdar return;
7722654012fSReza Sabdar }
7732654012fSReza Sabdar if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
7742654012fSReza Sabdar NDMP_LOG(LOG_INFO, "Tape device opened in read-only mode");
7752654012fSReza Sabdar reply.error = NDMP_PERMISSION_ERR;
7762654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
7772654012fSReza Sabdar "sending tape_write reply");
7782654012fSReza Sabdar return;
7792654012fSReza Sabdar }
7802654012fSReza Sabdar if (request->data_out.data_out_len == 0) {
7812654012fSReza Sabdar reply.error = NDMP_NO_ERR;
7822654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
7832654012fSReza Sabdar "sending tape_write reply");
7842654012fSReza Sabdar return;
7852654012fSReza Sabdar }
7862654012fSReza Sabdar
7872654012fSReza Sabdar /*
7882654012fSReza Sabdar * V4 suggests that this should not be accepted
7892654012fSReza Sabdar * when mover is in listen or active state
7902654012fSReza Sabdar */
7912654012fSReza Sabdar if (session->ns_protocol_version == NDMPV4 &&
7922654012fSReza Sabdar (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
7932654012fSReza Sabdar session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
7942654012fSReza Sabdar
7952654012fSReza Sabdar reply.error = NDMP_DEVICE_BUSY_ERR;
7962654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
7972654012fSReza Sabdar "sending tape_write reply");
7982654012fSReza Sabdar return;
7992654012fSReza Sabdar }
8002654012fSReza Sabdar
8012654012fSReza Sabdar n = write(session->ns_tape.td_fd, request->data_out.data_out_val,
8022654012fSReza Sabdar request->data_out.data_out_len);
8032654012fSReza Sabdar
804*9ee94b97SJan Kryl if (n < 0) {
8052654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape write error: %m.");
8062654012fSReza Sabdar reply.error = NDMP_IO_ERR;
807*9ee94b97SJan Kryl } else if (n == 0) {
808*9ee94b97SJan Kryl NDMP_LOG(LOG_INFO, "EOM detected");
809*9ee94b97SJan Kryl reply.error = NDMP_EOM_ERR;
8102654012fSReza Sabdar } else {
811*9ee94b97SJan Kryl NS_ADD(wtape, n);
8122654012fSReza Sabdar reply.count = n;
8132654012fSReza Sabdar reply.error = NDMP_NO_ERR;
814*9ee94b97SJan Kryl
815*9ee94b97SJan Kryl if (n < request->data_out.data_out_len)
816*9ee94b97SJan Kryl NDMP_LOG(LOG_DEBUG,
817*9ee94b97SJan Kryl "EOM is coming (partial write of %d bytes)", n);
8182654012fSReza Sabdar }
8192654012fSReza Sabdar
8202654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
8212654012fSReza Sabdar "sending tape_write reply");
8222654012fSReza Sabdar }
8232654012fSReza Sabdar
8242654012fSReza Sabdar /*
8252654012fSReza Sabdar * ndmpd_tape_read_v3
8262654012fSReza Sabdar *
827*9ee94b97SJan Kryl * This handler handles tape_read requests. This interface is a non-buffered
828*9ee94b97SJan Kryl * interface. Each read request maps directly to a read to the tape device. It
829*9ee94b97SJan Kryl * is the responsibility of the NDMP client to issue read requests with a
830*9ee94b97SJan Kryl * length that is at least as large as the record size used write the tape. The
831*9ee94b97SJan Kryl * tape driver always reads a full record. Data is discarded if the read
832*9ee94b97SJan Kryl * request is smaller than the record size. It is the responsibility of the
833*9ee94b97SJan Kryl * NDMP client to ensure that the length is a multiple of the tape block size
834*9ee94b97SJan Kryl * if the tape device is in fixed block mode.
835*9ee94b97SJan Kryl *
836*9ee94b97SJan Kryl * A logical end of tape will return less bytes than requested, and one more
837*9ee94b97SJan Kryl * request to read will give 0 and NDMP_EOM_ERR. All subsequent reads will
838*9ee94b97SJan Kryl * return NDMP_EOM_ERR until the tape is repositioned.
8392654012fSReza Sabdar *
8402654012fSReza Sabdar * Parameters:
8412654012fSReza Sabdar * connection (input) - connection handle.
8422654012fSReza Sabdar * body (input) - request message body.
8432654012fSReza Sabdar */
8442654012fSReza Sabdar void
ndmpd_tape_read_v3(ndmp_connection_t * connection,void * body)8452654012fSReza Sabdar ndmpd_tape_read_v3(ndmp_connection_t *connection, void *body)
8462654012fSReza Sabdar {
8472654012fSReza Sabdar ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
8482654012fSReza Sabdar ndmp_tape_read_reply reply;
8492654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
8502654012fSReza Sabdar char *buf;
851*9ee94b97SJan Kryl int n;
8522654012fSReza Sabdar
8532654012fSReza Sabdar reply.data_in.data_in_len = 0;
8542654012fSReza Sabdar
8552654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
8562654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
8572654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
8582654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
8592654012fSReza Sabdar "sending tape_read reply");
8602654012fSReza Sabdar return;
8612654012fSReza Sabdar }
8622654012fSReza Sabdar if (request->count == 0) {
8632654012fSReza Sabdar reply.error = NDMP_NO_ERR;
8642654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
8652654012fSReza Sabdar "sending tape_read reply");
8662654012fSReza Sabdar return;
8672654012fSReza Sabdar }
8682654012fSReza Sabdar
8692654012fSReza Sabdar /*
8702654012fSReza Sabdar * V4 suggests that this should not be accepted
8712654012fSReza Sabdar * when mover is in listen or active state
8722654012fSReza Sabdar */
8732654012fSReza Sabdar if (session->ns_protocol_version == NDMPV4 &&
8742654012fSReza Sabdar (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
8752654012fSReza Sabdar session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
8762654012fSReza Sabdar
8772654012fSReza Sabdar reply.error = NDMP_DEVICE_BUSY_ERR;
8782654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
8792654012fSReza Sabdar "sending tape_read reply");
8802654012fSReza Sabdar return;
8812654012fSReza Sabdar }
8822654012fSReza Sabdar
8832654012fSReza Sabdar if ((buf = ndmp_malloc(request->count)) == NULL) {
8842654012fSReza Sabdar reply.error = NDMP_NO_MEM_ERR;
8852654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
8862654012fSReza Sabdar "sending tape_read reply");
8872654012fSReza Sabdar return;
8882654012fSReza Sabdar }
8892654012fSReza Sabdar
8902654012fSReza Sabdar n = read(session->ns_tape.td_fd, buf, request->count);
8912654012fSReza Sabdar if (n < 0) {
8922654012fSReza Sabdar /*
8932654012fSReza Sabdar * This fix is for Symantec during importing
8942654012fSReza Sabdar * of spanned data between the tapes.
8952654012fSReza Sabdar */
8962654012fSReza Sabdar if (errno == ENOSPC) {
8972654012fSReza Sabdar reply.error = NDMP_EOF_ERR;
898*9ee94b97SJan Kryl }
899*9ee94b97SJan Kryl /*
900*9ee94b97SJan Kryl * If at beginning of file and read fails with EIO, then it's
901*9ee94b97SJan Kryl * repeated attempt to read at EOT.
902*9ee94b97SJan Kryl */
903*9ee94b97SJan Kryl else if (errno == EIO && tape_is_at_bof(session)) {
904*9ee94b97SJan Kryl NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
905*9ee94b97SJan Kryl reply.error = NDMP_EOM_ERR;
906*9ee94b97SJan Kryl }
907*9ee94b97SJan Kryl /*
908*9ee94b97SJan Kryl * According to NDMPv4 spec preferred error code when
909*9ee94b97SJan Kryl * trying to read from blank tape is NDMP_EOM_ERR.
910*9ee94b97SJan Kryl */
911*9ee94b97SJan Kryl else if (errno == EIO && tape_is_at_bot(session)) {
912*9ee94b97SJan Kryl NDMP_LOG(LOG_ERR, "Blank tape detected, returning EOM");
913*9ee94b97SJan Kryl reply.error = NDMP_EOM_ERR;
9142654012fSReza Sabdar } else {
9152654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape read error: %m.");
9162654012fSReza Sabdar reply.error = NDMP_IO_ERR;
9172654012fSReza Sabdar }
9182654012fSReza Sabdar } else if (n == 0) {
919*9ee94b97SJan Kryl if (tape_is_at_bof(session)) {
920*9ee94b97SJan Kryl NDMP_LOG(LOG_DEBUG, "EOT detected");
9212654012fSReza Sabdar reply.error = NDMP_EOM_ERR;
9222654012fSReza Sabdar } else {
923*9ee94b97SJan Kryl /* reposition the tape to BOT side of FM */
924*9ee94b97SJan Kryl fm_dance(session);
925*9ee94b97SJan Kryl NDMP_LOG(LOG_DEBUG, "EOF detected");
9262654012fSReza Sabdar reply.error = NDMP_EOF_ERR;
9272654012fSReza Sabdar }
9282654012fSReza Sabdar } else {
9292654012fSReza Sabdar session->ns_tape.td_pos += n;
9302654012fSReza Sabdar reply.data_in.data_in_len = n;
9312654012fSReza Sabdar reply.data_in.data_in_val = buf;
9322654012fSReza Sabdar reply.error = NDMP_NO_ERR;
9332654012fSReza Sabdar NS_ADD(rtape, n);
9342654012fSReza Sabdar }
9352654012fSReza Sabdar
9362654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
9372654012fSReza Sabdar free(buf);
9382654012fSReza Sabdar }
9392654012fSReza Sabdar
9402654012fSReza Sabdar
9412654012fSReza Sabdar /*
9422654012fSReza Sabdar * ************************************************************************
9432654012fSReza Sabdar * NDMP V4 HANDLERS
9442654012fSReza Sabdar * ************************************************************************
9452654012fSReza Sabdar */
9462654012fSReza Sabdar
9472654012fSReza Sabdar /*
9482654012fSReza Sabdar * ndmpd_tape_get_state_v4
9492654012fSReza Sabdar *
9502654012fSReza Sabdar * This handler handles the ndmp_tape_get_state_request.
9512654012fSReza Sabdar * Status information for the currently open tape device is returned.
9522654012fSReza Sabdar *
9532654012fSReza Sabdar * Parameters:
9542654012fSReza Sabdar * connection (input) - connection handle.
9552654012fSReza Sabdar * body (input) - request message body.
9562654012fSReza Sabdar *
9572654012fSReza Sabdar * Returns:
9582654012fSReza Sabdar * void
9592654012fSReza Sabdar */
9602654012fSReza Sabdar /*ARGSUSED*/
9612654012fSReza Sabdar void
ndmpd_tape_get_state_v4(ndmp_connection_t * connection,void * body)9622654012fSReza Sabdar ndmpd_tape_get_state_v4(ndmp_connection_t *connection, void *body)
9632654012fSReza Sabdar {
9642654012fSReza Sabdar ndmp_tape_get_state_reply_v4 reply;
9652654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
9662654012fSReza Sabdar struct mtget mtstatus;
9672654012fSReza Sabdar struct mtdrivetype_request dtpr;
9682654012fSReza Sabdar struct mtdrivetype dtp;
9692654012fSReza Sabdar
9702654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
9712654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
9722654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
9732654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
9742654012fSReza Sabdar "sending tape_get_state reply");
9752654012fSReza Sabdar return;
9762654012fSReza Sabdar }
9772654012fSReza Sabdar
9782654012fSReza Sabdar /*
9792654012fSReza Sabdar * Need code to detect NDMP_TAPE_STATE_NOREWIND
9802654012fSReza Sabdar */
9812654012fSReza Sabdar
9822654012fSReza Sabdar if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
9832654012fSReza Sabdar NDMP_LOG(LOG_ERR,
9842654012fSReza Sabdar "Failed to get status information from tape: %m.");
9852654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
9862654012fSReza Sabdar
9872654012fSReza Sabdar reply.error = NDMP_IO_ERR;
9882654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
9892654012fSReza Sabdar "sending tape_get_state reply");
9902654012fSReza Sabdar return;
9912654012fSReza Sabdar }
9922654012fSReza Sabdar
9932654012fSReza Sabdar dtpr.size = sizeof (struct mtdrivetype);
9942654012fSReza Sabdar dtpr.mtdtp = &dtp;
9952654012fSReza Sabdar if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
9962654012fSReza Sabdar NDMP_LOG(LOG_ERR,
9972654012fSReza Sabdar "Failed to get drive type information from tape: %m.");
9982654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
9992654012fSReza Sabdar
10002654012fSReza Sabdar reply.error = NDMP_IO_ERR;
10012654012fSReza Sabdar ndmp_send_reply(connection, (void *)&reply,
10022654012fSReza Sabdar "sending tape_get_state reply");
10032654012fSReza Sabdar return;
10042654012fSReza Sabdar }
10052654012fSReza Sabdar
100686c48bbfSReza Sabdar reply.flags = NDMP_TAPE_NOREWIND;
10072654012fSReza Sabdar
10082654012fSReza Sabdar reply.file_num = mtstatus.mt_fileno;
10092654012fSReza Sabdar reply.soft_errors = 0;
10102654012fSReza Sabdar reply.block_size = dtp.bsize;
10112654012fSReza Sabdar
10122654012fSReza Sabdar if (dtp.bsize == 0)
10132654012fSReza Sabdar reply.blockno = mtstatus.mt_blkno;
10142654012fSReza Sabdar else
1015*9ee94b97SJan Kryl reply.blockno = mtstatus.mt_blkno /
10162654012fSReza Sabdar (session->ns_mover.md_record_size / dtp.bsize);
10172654012fSReza Sabdar
1018*9ee94b97SJan Kryl reply.total_space = long_long_to_quad(0LL); /* not supported */
1019*9ee94b97SJan Kryl reply.space_remain = long_long_to_quad(0LL); /* not supported */
10202654012fSReza Sabdar reply.soft_errors = 0;
10212654012fSReza Sabdar reply.unsupported = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
10222654012fSReza Sabdar NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
10232654012fSReza Sabdar NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
10242654012fSReza Sabdar NDMP_TAPE_STATE_PARTITION_INVALID;
10252654012fSReza Sabdar
10262654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "f 0x%x, fnum %d, bsize %d, bno: %d",
10272654012fSReza Sabdar reply.flags, reply.file_num, reply.block_size, reply.blockno);
10282654012fSReza Sabdar
10292654012fSReza Sabdar reply.error = NDMP_NO_ERR;
10302654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
10312654012fSReza Sabdar "sending tape_get_state reply");
10322654012fSReza Sabdar }
10332654012fSReza Sabdar /*
10342654012fSReza Sabdar * ndmpd_tape_close_v4
10352654012fSReza Sabdar *
10362654012fSReza Sabdar * This handler (v4) closes the currently open tape device.
10372654012fSReza Sabdar *
10382654012fSReza Sabdar * Parameters:
10392654012fSReza Sabdar * connection (input) - connection handle.
10402654012fSReza Sabdar * body (input) - request message body.
10412654012fSReza Sabdar *
10422654012fSReza Sabdar * Returns:
10432654012fSReza Sabdar * void
10442654012fSReza Sabdar */
10452654012fSReza Sabdar /*ARGSUSED*/
10462654012fSReza Sabdar void
ndmpd_tape_close_v4(ndmp_connection_t * connection,void * body)10472654012fSReza Sabdar ndmpd_tape_close_v4(ndmp_connection_t *connection, void *body)
10482654012fSReza Sabdar {
10492654012fSReza Sabdar ndmp_tape_close_reply reply;
10502654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
10512654012fSReza Sabdar
10522654012fSReza Sabdar if (session->ns_tape.td_fd == -1) {
10532654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape device is not open.");
10542654012fSReza Sabdar reply.error = NDMP_DEV_NOT_OPEN_ERR;
10552654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
10562654012fSReza Sabdar "sending tape_close reply");
10572654012fSReza Sabdar return;
10582654012fSReza Sabdar }
10592654012fSReza Sabdar
10602654012fSReza Sabdar /*
10612654012fSReza Sabdar * V4 suggests that this should not be accepted
10622654012fSReza Sabdar * when mover is in listen or active state
10632654012fSReza Sabdar */
10642654012fSReza Sabdar if (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
10652654012fSReza Sabdar session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
10662654012fSReza Sabdar
10672654012fSReza Sabdar reply.error = NDMP_DEVICE_BUSY_ERR;
10682654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
10692654012fSReza Sabdar "sending tape_close reply");
10702654012fSReza Sabdar return;
10712654012fSReza Sabdar }
10722654012fSReza Sabdar
10732654012fSReza Sabdar common_tape_close(connection);
10742654012fSReza Sabdar }
10752654012fSReza Sabdar
10762654012fSReza Sabdar
10772654012fSReza Sabdar /*
10782654012fSReza Sabdar * ************************************************************************
10792654012fSReza Sabdar * LOCALS
10802654012fSReza Sabdar * ************************************************************************
10812654012fSReza Sabdar */
10822654012fSReza Sabdar /*
10832654012fSReza Sabdar * tape_open_send_reply
10842654012fSReza Sabdar *
10852654012fSReza Sabdar * Send a reply to the tape open message
10862654012fSReza Sabdar *
10872654012fSReza Sabdar * Parameters:
10882654012fSReza Sabdar * connection (input) - connection handle.
10892654012fSReza Sabdar * err (input) - NDMP error
10902654012fSReza Sabdar *
10912654012fSReza Sabdar * Returns:
10922654012fSReza Sabdar * void
10932654012fSReza Sabdar */
10942654012fSReza Sabdar static void
tape_open_send_reply(ndmp_connection_t * connection,int err)10952654012fSReza Sabdar tape_open_send_reply(ndmp_connection_t *connection, int err)
10962654012fSReza Sabdar {
10972654012fSReza Sabdar ndmp_tape_open_reply reply;
10982654012fSReza Sabdar
10992654012fSReza Sabdar reply.error = err;
11002654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply, "sending tape_open reply");
11012654012fSReza Sabdar }
11022654012fSReza Sabdar
11032654012fSReza Sabdar /*
11042654012fSReza Sabdar * unbuffered_read
11052654012fSReza Sabdar *
11062654012fSReza Sabdar * Perform tape read without read-ahead
11072654012fSReza Sabdar *
11082654012fSReza Sabdar * Parameters:
11092654012fSReza Sabdar * session (input) - session handle
11102654012fSReza Sabdar * bp (output) - read buffer
11112654012fSReza Sabdar * wanted (input) - number of bytes wanted
11122654012fSReza Sabdar * reply (output) - tape read reply message
11132654012fSReza Sabdar *
11142654012fSReza Sabdar * Returns:
11152654012fSReza Sabdar * void
11162654012fSReza Sabdar */
11172654012fSReza Sabdar static void
unbuffered_read(ndmpd_session_t * session,char * buf,long wanted,ndmp_tape_read_reply * reply)11182654012fSReza Sabdar unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
11192654012fSReza Sabdar ndmp_tape_read_reply *reply)
11202654012fSReza Sabdar {
11212654012fSReza Sabdar int n, len;
11222654012fSReza Sabdar
11232654012fSReza Sabdar n = read(session->ns_tape.td_fd, buf, wanted);
11242654012fSReza Sabdar if (n < 0) {
11252654012fSReza Sabdar /*
11262654012fSReza Sabdar * This fix is for Symantec during importing
11272654012fSReza Sabdar * of spanned data between the tapes.
11282654012fSReza Sabdar */
11292654012fSReza Sabdar if (errno == ENOSPC) {
11302654012fSReza Sabdar reply->error = NDMP_EOF_ERR;
11312654012fSReza Sabdar } else {
11322654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Tape read error: %m.");
11332654012fSReza Sabdar reply->error = NDMP_IO_ERR;
11342654012fSReza Sabdar }
11352654012fSReza Sabdar } else if (n == 0) {
11362654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "NDMP_EOF_ERR");
11372654012fSReza Sabdar
11382654012fSReza Sabdar reply->error = NDMP_EOF_ERR;
11392654012fSReza Sabdar
11402654012fSReza Sabdar (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
11412654012fSReza Sabdar
11422654012fSReza Sabdar len = strlen(NDMP_EOM_MAGIC);
11432654012fSReza Sabdar (void) memset(buf, 0, len);
11442654012fSReza Sabdar n = read(session->ns_tape.td_fd, buf, len);
11452654012fSReza Sabdar buf[len] = '\0';
11462654012fSReza Sabdar
11472654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Checking EOM: nread %d [%s]", n, buf);
11482654012fSReza Sabdar
11492654012fSReza Sabdar (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
11502654012fSReza Sabdar
11512654012fSReza Sabdar if (strncmp(buf, NDMP_EOM_MAGIC, len) != 0)
11522654012fSReza Sabdar (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
11532654012fSReza Sabdar } else {
11542654012fSReza Sabdar session->ns_tape.td_pos += n;
11552654012fSReza Sabdar reply->data_in.data_in_len = n;
11562654012fSReza Sabdar reply->data_in.data_in_val = buf;
11572654012fSReza Sabdar reply->error = NDMP_NO_ERR;
11582654012fSReza Sabdar NS_ADD(rtape, n);
11592654012fSReza Sabdar }
11602654012fSReza Sabdar }
11612654012fSReza Sabdar
11622654012fSReza Sabdar
11632654012fSReza Sabdar /*
11642654012fSReza Sabdar * validmode
11652654012fSReza Sabdar *
11662654012fSReza Sabdar * Check the tape read mode is valid
11672654012fSReza Sabdar */
11682654012fSReza Sabdar static boolean_t
validmode(int mode)11692654012fSReza Sabdar validmode(int mode)
11702654012fSReza Sabdar {
11712654012fSReza Sabdar boolean_t rv;
11722654012fSReza Sabdar
11732654012fSReza Sabdar switch (mode) {
11742654012fSReza Sabdar case NDMP_TAPE_READ_MODE:
11752654012fSReza Sabdar case NDMP_TAPE_WRITE_MODE:
11762654012fSReza Sabdar case NDMP_TAPE_RAW1_MODE:
11772654012fSReza Sabdar case NDMP_TAPE_RAW2_MODE:
11782654012fSReza Sabdar rv = TRUE;
11792654012fSReza Sabdar break;
11802654012fSReza Sabdar default:
11812654012fSReza Sabdar rv = FALSE;
11822654012fSReza Sabdar }
11832654012fSReza Sabdar
11842654012fSReza Sabdar return (rv);
11852654012fSReza Sabdar }
11862654012fSReza Sabdar
11872654012fSReza Sabdar
11882654012fSReza Sabdar /*
11892654012fSReza Sabdar * common_tape_open
11902654012fSReza Sabdar *
11912654012fSReza Sabdar * Generic function for opening the tape for all versions
11922654012fSReza Sabdar *
11932654012fSReza Sabdar * Parameters:
11942654012fSReza Sabdar * connection (input) - connection handle.
11952654012fSReza Sabdar * devname (input) - tape device name to open.
11962654012fSReza Sabdar * ndmpmode (input) - mode of opening (read, write, raw)
11972654012fSReza Sabdar *
11982654012fSReza Sabdar * Returns:
11992654012fSReza Sabdar * void
12002654012fSReza Sabdar */
12012654012fSReza Sabdar static void
common_tape_open(ndmp_connection_t * connection,char * devname,int ndmpmode)12022654012fSReza Sabdar common_tape_open(ndmp_connection_t *connection, char *devname, int ndmpmode)
12032654012fSReza Sabdar {
12042654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
12052654012fSReza Sabdar char adptnm[SCSI_MAX_NAME];
12062654012fSReza Sabdar int err;
12072654012fSReza Sabdar int mode;
12082654012fSReza Sabdar int sid, lun;
12092654012fSReza Sabdar scsi_adapter_t *sa;
12102654012fSReza Sabdar int devid;
12112654012fSReza Sabdar
12122654012fSReza Sabdar err = NDMP_NO_ERR;
12132654012fSReza Sabdar
12142654012fSReza Sabdar if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
12152654012fSReza Sabdar NDMP_LOG(LOG_INFO,
12162654012fSReza Sabdar "Connection already has a tape or scsi device open");
12172654012fSReza Sabdar err = NDMP_DEVICE_OPENED_ERR;
12182654012fSReza Sabdar } else if (!validmode(ndmpmode))
12192654012fSReza Sabdar err = NDMP_ILLEGAL_ARGS_ERR;
12202654012fSReza Sabdar if ((sa = scsi_get_adapter(0)) != NULL) {
12212654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Adapter device opened: %s", devname);
12222654012fSReza Sabdar (void) strlcpy(adptnm, devname, SCSI_MAX_NAME-2);
12232654012fSReza Sabdar adptnm[SCSI_MAX_NAME-1] = '\0';
12242654012fSReza Sabdar sid = lun = -1;
12252654012fSReza Sabdar }
12262654012fSReza Sabdar if (sa) {
12272654012fSReza Sabdar scsi_find_sid_lun(sa, devname, &sid, &lun);
12282654012fSReza Sabdar if (ndmp_open_list_find(devname, sid, lun) == 0 &&
12292654012fSReza Sabdar (devid = open(devname, O_RDWR | O_NDELAY)) < 0) {
12302654012fSReza Sabdar NDMP_LOG(LOG_ERR,
12312654012fSReza Sabdar "Failed to open device %s: %m.", devname);
12322654012fSReza Sabdar err = NDMP_NO_DEVICE_ERR;
12332654012fSReza Sabdar } else {
12342654012fSReza Sabdar (void) close(devid);
12352654012fSReza Sabdar }
12362654012fSReza Sabdar } else {
12372654012fSReza Sabdar NDMP_LOG(LOG_ERR, "%s: No such tape device.", devname);
12382654012fSReza Sabdar err = NDMP_NO_DEVICE_ERR;
12392654012fSReza Sabdar }
12402654012fSReza Sabdar
12412654012fSReza Sabdar if (err != NDMP_NO_ERR) {
12422654012fSReza Sabdar tape_open_send_reply(connection, err);
12432654012fSReza Sabdar return;
12442654012fSReza Sabdar }
12452654012fSReza Sabdar
12462654012fSReza Sabdar /*
12472654012fSReza Sabdar * If tape is not opened in raw mode and tape is not loaded
12482654012fSReza Sabdar * return error.
12492654012fSReza Sabdar */
12502654012fSReza Sabdar if (ndmpmode != NDMP_TAPE_RAW1_MODE &&
12512654012fSReza Sabdar ndmpmode != NDMP_TAPE_RAW2_MODE &&
12522654012fSReza Sabdar !is_tape_unit_ready(adptnm, 0)) {
12532654012fSReza Sabdar tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
12542654012fSReza Sabdar return;
12552654012fSReza Sabdar }
12562654012fSReza Sabdar
12572654012fSReza Sabdar mode = (ndmpmode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
12582654012fSReza Sabdar mode |= O_NDELAY;
12592654012fSReza Sabdar session->ns_tape.td_fd = open(devname, mode);
12602654012fSReza Sabdar if (session->ns_protocol_version == NDMPV4 &&
12612654012fSReza Sabdar session->ns_tape.td_fd < 0 &&
12622654012fSReza Sabdar ndmpmode == NDMP_TAPE_RAW_MODE && errno == EACCES) {
12632654012fSReza Sabdar /*
12642654012fSReza Sabdar * V4 suggests that if the tape is open in raw mode
12652654012fSReza Sabdar * and could not be opened with write access, it should
12662654012fSReza Sabdar * be opened read only instead.
12672654012fSReza Sabdar */
12682654012fSReza Sabdar ndmpmode = NDMP_TAPE_READ_MODE;
12692654012fSReza Sabdar session->ns_tape.td_fd = open(devname, O_RDONLY);
12702654012fSReza Sabdar }
12712654012fSReza Sabdar if (session->ns_tape.td_fd < 0) {
12722654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
12732654012fSReza Sabdar devname);
12742654012fSReza Sabdar switch (errno) {
12752654012fSReza Sabdar case EACCES:
12762654012fSReza Sabdar err = NDMP_WRITE_PROTECT_ERR;
12772654012fSReza Sabdar break;
12782654012fSReza Sabdar case ENOENT:
12792654012fSReza Sabdar err = NDMP_NO_DEVICE_ERR;
12802654012fSReza Sabdar break;
12812654012fSReza Sabdar case EBUSY:
12822654012fSReza Sabdar err = NDMP_DEVICE_BUSY_ERR;
12832654012fSReza Sabdar break;
12842654012fSReza Sabdar case EPERM:
12852654012fSReza Sabdar err = NDMP_PERMISSION_ERR;
12862654012fSReza Sabdar break;
12872654012fSReza Sabdar default:
12882654012fSReza Sabdar err = NDMP_IO_ERR;
12892654012fSReza Sabdar }
12902654012fSReza Sabdar
12912654012fSReza Sabdar tape_open_send_reply(connection, err);
12922654012fSReza Sabdar return;
12932654012fSReza Sabdar }
12942654012fSReza Sabdar
12952654012fSReza Sabdar switch (ndmp_open_list_add(connection,
12962654012fSReza Sabdar adptnm, sid, lun, session->ns_tape.td_fd)) {
12972654012fSReza Sabdar case 0:
12982654012fSReza Sabdar err = NDMP_NO_ERR;
12992654012fSReza Sabdar break;
13002654012fSReza Sabdar case EBUSY:
13012654012fSReza Sabdar err = NDMP_DEVICE_BUSY_ERR;
13022654012fSReza Sabdar break;
13032654012fSReza Sabdar case ENOMEM:
13042654012fSReza Sabdar err = NDMP_NO_MEM_ERR;
13052654012fSReza Sabdar break;
13062654012fSReza Sabdar default:
13072654012fSReza Sabdar err = NDMP_IO_ERR;
13082654012fSReza Sabdar }
13092654012fSReza Sabdar if (err != NDMP_NO_ERR) {
13102654012fSReza Sabdar tape_open_send_reply(connection, err);
13112654012fSReza Sabdar return;
13122654012fSReza Sabdar }
13132654012fSReza Sabdar
13142654012fSReza Sabdar session->ns_tape.td_mode = ndmpmode;
13152654012fSReza Sabdar session->ns_tape.td_sid = sid;
13162654012fSReza Sabdar session->ns_tape.td_lun = lun;
13172654012fSReza Sabdar (void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
13182654012fSReza Sabdar session->ns_tape.td_record_count = 0;
13192654012fSReza Sabdar
13202654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
13212654012fSReza Sabdar
13222654012fSReza Sabdar tape_open_send_reply(connection, NDMP_NO_ERR);
13232654012fSReza Sabdar }
13242654012fSReza Sabdar
13252654012fSReza Sabdar
13262654012fSReza Sabdar /*
13272654012fSReza Sabdar * common_tape_close
13282654012fSReza Sabdar *
13292654012fSReza Sabdar * Generic function for closing the tape
13302654012fSReza Sabdar *
13312654012fSReza Sabdar * Parameters:
13322654012fSReza Sabdar * connection (input) - connection handle.
13332654012fSReza Sabdar *
13342654012fSReza Sabdar * Returns:
13352654012fSReza Sabdar * void
13362654012fSReza Sabdar */
13372654012fSReza Sabdar static void
common_tape_close(ndmp_connection_t * connection)13382654012fSReza Sabdar common_tape_close(ndmp_connection_t *connection)
13392654012fSReza Sabdar {
13402654012fSReza Sabdar ndmpd_session_t *session = ndmp_get_client_data(connection);
13412654012fSReza Sabdar ndmp_tape_close_reply reply;
13422654012fSReza Sabdar
13432654012fSReza Sabdar (void) ndmp_open_list_del(session->ns_tape.td_adapter_name,
13442654012fSReza Sabdar session->ns_tape.td_sid, session->ns_tape.td_lun);
13452654012fSReza Sabdar (void) close(session->ns_tape.td_fd);
13462654012fSReza Sabdar session->ns_tape.td_fd = -1;
13472654012fSReza Sabdar session->ns_tape.td_sid = 0;
13482654012fSReza Sabdar session->ns_tape.td_lun = 0;
13492654012fSReza Sabdar (void) memset(session->ns_tape.td_adapter_name, 0,
13502654012fSReza Sabdar sizeof (session->ns_tape.td_adapter_name));
13512654012fSReza Sabdar session->ns_tape.td_record_count = 0;
13522654012fSReza Sabdar
13532654012fSReza Sabdar reply.error = NDMP_NO_ERR;
13542654012fSReza Sabdar ndmp_send_reply(connection, (void *) &reply,
13552654012fSReza Sabdar "sending tape_close reply");
13562654012fSReza Sabdar }
13572654012fSReza Sabdar
13582654012fSReza Sabdar /*
13592654012fSReza Sabdar * tape_open
13602654012fSReza Sabdar *
13612654012fSReza Sabdar * Will try to open the tape with the given flags and
13622654012fSReza Sabdar * path using the given retries and delay intervals
13632654012fSReza Sabdar */
13642654012fSReza Sabdar int
tape_open(char * path,int flags)13652654012fSReza Sabdar tape_open(char *path, int flags)
13662654012fSReza Sabdar {
13672654012fSReza Sabdar int fd;
13682654012fSReza Sabdar int i = 0;
13692654012fSReza Sabdar
13702654012fSReza Sabdar while ((fd = open(path, flags)) == -1 &&
13712654012fSReza Sabdar i++ < ndmp_tape_open_retries) {
13722654012fSReza Sabdar if (errno != EBUSY)
13732654012fSReza Sabdar break;
13742654012fSReza Sabdar (void) usleep(ndmp_tape_open_delay);
13752654012fSReza Sabdar }
13762654012fSReza Sabdar return (fd);
13772654012fSReza Sabdar }
1378