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