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