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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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