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.
 
 
  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;
 
 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;
 
 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 
 
 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  *
 
 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 
 
 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 
 
 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  */
 
 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);
 
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
 
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;
 
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;
 
 | 
 
 
  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.
 
 
  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;
 
 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;
 
 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 
 
 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  *
 
 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 
 
 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 
 
 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  */
 
 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);
 
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
 
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;
 
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;
 
 |