Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  *
     21  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     22  * Use is subject to license terms.
     23  */
     24 
     25 
     26 #include <thread.h>
     27 #include <ctype.h>
     28 #include <sys/types.h>
     29 #include <sys/mkdev.h>
     30 #include <sys/file.h>
     31 #include <synch.h>
     32 #include <unistd.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <time.h>
     36 #include <stropts.h>
     37 #include <errno.h>
     38 #include <string.h>
     39 #include <syslog.h>
     40 #include <fcntl.h>
     41 #include <sys/stat.h>
     42 #include <pthread.h>
     43 #include <sys/scsi/generic/sense.h>
     44 #include <sys/scsi/impl/uscsi.h>
     45 #include <mms_list.h>
     46 #include <dmd_impl.h>
     47 #include <dm_impl.h>
     48 #include <dm_msg.h>
     49 #include <mms_trace.h>
     50 #include <mms_dmd.h>
     51 #include <dm_proto.h>
     52 #include <mms_strapp.h>
     53 
     54 static	char *_SrcFile = __FILE__;
     55 
     56 void
     57 dm_get_request(void)
     58 {
     59 	/*
     60 	 * Get request from driver
     61 	 */
     62 	if (ioctl(wka->dm_drm_fd, DRM_REQUEST, &wka->dm_reqbuf)) {
     63 		/*
     64 		 * No request, process error
     65 		 */
     66 		TRACE((MMS_DEBUG, "dm_get_request: "
     67 		    "No request: %s", strerror(errno)));
     68 		return;
     69 	}
     70 	wka->dm_request = &wka->dm_reqbuf;
     71 }
     72 
     73 void
     74 dm_proc_request(void)
     75 {
     76 	int		rc = 0;
     77 	drm_request_t	*req;
     78 	drm_reply_t	rep;
     79 	tapepos_t	pos;
     80 	char		dbuf[4096];
     81 
     82 	dm_msg_destroy();			/* cleanup any left over msg */
     83 
     84 	if (DRV_CALL(drv_get_pos, (&pos)) == 0) {
     85 		TRACE((MMS_DEBUG, "dm_proc_request: Entered at position %lld",
     86 		    pos.lgclblkno));
     87 	}
     88 
     89 	memset(&rep, 0, sizeof (rep));
     90 	req = wka->dm_request;
     91 	(void) mms_trace_dump((char *)req, sizeof (drm_request_t), dbuf,
     92 	    sizeof (dbuf));
     93 	TRACE((MMS_DEBUG, "dm_proc_request: Request:\n%s", dbuf));
     94 
     95 	/*
     96 	 * Save I/O counts
     97 	 */
     98 	drv->drv_rdbytes += req->drm_req_rdbytes;
     99 	drv->drv_wrbytes += req->drm_req_wrbytes;
    100 
    101 	if (req->drm_req_type != DRM_REQ_OPEN &&
    102 	    req->drm_req_type != DRM_REQ_CLOSE) {
    103 		/*
    104 		 * If not an open or close request and not in user data,
    105 		 * then allow only status requests.
    106 		 */
    107 		if ((drv->drv_flags & DRV_UDATA) == 0 &&
    108 		    req->drm_req_type != DRM_REQ_MTGET) {
    109 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    110 			    "file not positioned correctly"));
    111 			rc = EACCES;
    112 			goto done;
    113 		}
    114 	}
    115 
    116 	if (req->drm_req_flags & DRM_REQ_MOVED) {
    117 		TRACE((MMS_DEBUG, "dm_get_request: Tape Moved"));
    118 		drv->drv_flags &= ~(DRV_VALID_STAT | DRV_MOVE_FLAGS);
    119 	}
    120 
    121 	memset(&rep, 0, sizeof (drm_reply_t));
    122 	switch (req->drm_req_type) {
    123 	case DRM_REQ_MTIOCTOP:
    124 		TRACE((MMS_INFO, "dm_get_request: "
    125 		    "Got request DRM_REQ_MTIOCTOP"));
    126 		rc = dm_ioctl_mtiocltop(req, &rep);
    127 		break;
    128 	case DRM_REQ_MTIOCLTOP:
    129 		TRACE((MMS_INFO, "dm_get_request: "
    130 		    "Got request DRM_REQ_MTIOCLTOP"));
    131 		rc = dm_ioctl_mtiocltop(req, &rep);
    132 		break;
    133 	case DRM_REQ_OPEN:
    134 		TRACE((MMS_INFO, "dm_get_request: "
    135 		    "Got open request DRM_REQ_OPEN"));
    136 		rc = dm_open(req, &rep);
    137 		break;
    138 	case DRM_REQ_CLOSE:
    139 		TRACE((MMS_INFO, "dm_get_request: "
    140 		    "Got close request DRM_REQ_CLOSE"));
    141 		rc = dm_close();
    142 		break;
    143 	case DRM_REQ_READ:
    144 		TRACE((MMS_INFO, "dm_get_request: "
    145 		    "Got read request DRM_REQ_READ"));
    146 		rc = dm_read(&rep);
    147 		break;
    148 	case DRM_REQ_READ_TM:
    149 		TRACE((MMS_INFO, "dm_get_request: "
    150 		    "Got read FM request DRM_REQ_READ_TM"));
    151 		rc = dm_read_tm(req);
    152 		break;
    153 	case DRM_REQ_READ_ERR:
    154 		TRACE((MMS_INFO, "dm_get_request: "
    155 		    "Got read ERR request DRM_REQ_READ_ERR"));
    156 		rc = dm_read_err(req, &rep);
    157 		break;
    158 	case DRM_REQ_WRITE:
    159 		TRACE((MMS_INFO, "dm_get_request: "
    160 		    "Got write request DRM_REQ_WRITE"));
    161 		rc = dm_write(&rep);
    162 		break;
    163 	case DRM_REQ_WRITE0:
    164 		TRACE((MMS_INFO, "dm_get_request: "
    165 		    "Got write0 request DRM_REQ_WRITE0"));
    166 		rc = dm_write_0(req, &rep);
    167 		break;
    168 	case DRM_REQ_WRITE_ERR:
    169 		TRACE((MMS_INFO, "dm_get_request: "
    170 		    "Got write err request DRM_REQ_WRITE_ERR"));
    171 		rc = dm_write_err(req, &rep);
    172 		break;
    173 	case DRM_REQ_MTGET:
    174 		TRACE((MMS_INFO, "dm_get_request: "
    175 		    "Got request DRM_REQ_MTGET"));
    176 		rc = dm_ioctl_mtget(req, &rep);
    177 		break;
    178 	case DRM_REQ_CLRERR:
    179 		TRACE((MMS_INFO, "dm_get_request: "
    180 		    "Got request DRM_REQ_CLRERR"));
    181 		rc = dm_ioctl_clrerr(&rep);
    182 		break;
    183 	case DRM_REQ_BLK_LIMIT:
    184 		TRACE((MMS_INFO, "dm_get_request: "
    185 		    "Got request MMS_REQ_BLK_LIMIT"));
    186 		if (drv->drv_flags & DRV_FATAL) {
    187 			rc = EIO;
    188 			break;
    189 		}
    190 		rc = DRV_CALL(drv_blk_limit, (&rep.drm_blk_limit_rep));
    191 		break;
    192 	case DRM_REQ_GET_POS:
    193 		TRACE((MMS_INFO, "dm_get_request: "
    194 		    "Got request MMS_REQ_GET_POS"));
    195 		rc = dm_ioctl_getpos(&rep);
    196 		break;
    197 	case DRM_REQ_MTGETPOS:
    198 		TRACE((MMS_INFO, "dm_get_request: "
    199 		    "Got request MMS_REQ_GET_POS"));
    200 		rc = dm_ioctl_mtgetpos(&rep);
    201 		break;
    202 	case DRM_REQ_MTRESTPOS:
    203 		TRACE((MMS_INFO, "dm_get_request: "
    204 		    "Got request MMS_REQ_GET_POS"));
    205 		rc = dm_ioctl_mtrestpos(req);
    206 		break;
    207 	case DRM_REQ_LOCATE:
    208 		TRACE((MMS_INFO, "dm_get_request: "
    209 		    "Got request MMS_REQ_LOCATE"));
    210 		rc = dm_ioctl_locate(req);
    211 		break;
    212 	case DRM_REQ_GET_CAPACITY:
    213 		TRACE((MMS_INFO, "dm_get_request: "
    214 		    "Got request MMS_REQ_GET_CAPACITY"));
    215 		rc = dm_ioctl_get_capacity(&rep);
    216 		break;
    217 	case DRM_REQ_UPT_CAPACITY:
    218 		TRACE((MMS_INFO, "dm_get_request: "
    219 		    "Got request MMS_REQ_UPT_CAPACITY"));
    220 		rc = dm_ioctl_upt_capacity();
    221 		break;
    222 	case DRM_REQ_SET_DENSITY:
    223 		TRACE((MMS_INFO, "dm_get_request: "
    224 		    "Got request MMS_REQ_SET_DENSITY"));
    225 		rc = dm_ioctl_set_density();
    226 		break;
    227 	case DRM_REQ_GET_DENSITY:
    228 		TRACE((MMS_INFO, "dm_get_request: "
    229 		    "Got request MMS_REQ_GET_DENSITY"));
    230 		rc = dm_ioctl_get_density(&rep);
    231 		break;
    232 
    233 	default:
    234 		rc = EINVAL;
    235 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    236 		    "invalid request from driver %lld", req->drm_req_type));
    237 		rc = EINVAL;
    238 		break;
    239 	}
    240 
    241 done:
    242 	dm_msg_destroy();			/* clean up left over msg */
    243 	/*
    244 	 * If at EOF and don't have a valid EOF position, then get it.
    245 	 */
    246 	if (drv->drv_flags & DRV_EOF) {
    247 		(void) dm_get_eof_pos();
    248 	}
    249 
    250 	rep.drm_rep_rc = rc;
    251 	if (drv->drv_flags & DRV_EOF) {
    252 		TRACE((MMS_DEBUG, "dm_get_request: "
    253 		    "At EOF"));
    254 		rep.drm_rep_flags |= DRM_REP_EOF;
    255 	}
    256 
    257 	if (drv->drv_flags & DRV_FATAL) {
    258 		TRACE((MMS_DEBUG, "dm_get_request: "
    259 		    "Fatal error occured"));
    260 		rep.drm_rep_flags |= DRM_REP_FATAL;
    261 	}
    262 	if (drv->drv_flags & DRV_TERM_FILE) {
    263 		TRACE((MMS_DEBUG, "dm_get_request: "
    264 		    "Catch next read"));
    265 		rep.drm_rep_flags |= DRM_REP_NOTIFY_READ;
    266 	} else {
    267 		TRACE((MMS_DEBUG, "dm_get_request: "
    268 		    "Catch next write"));
    269 		rep.drm_rep_flags |= DRM_REP_NOTIFY_WRITE;
    270 	}
    271 	if (req->drm_req_flags & DRM_REQ_NOTIFY_READ) {
    272 		TRACE((MMS_DEBUG, "dm_get_request: "
    273 		    "Notify read in effect"));
    274 		rep.drm_rep_flags |= DRM_REP_NOTIFY_READ;
    275 	}
    276 	if (req->drm_req_flags & DRM_REQ_NOTIFY_WRITE) {
    277 		TRACE((MMS_DEBUG, "dm_get_request: "
    278 		    "Notify write in effect"));
    279 		rep.drm_rep_flags |= DRM_REP_NOTIFY_WRITE;
    280 	}
    281 
    282 	if (DRV_CALL(drv_get_pos, (&pos)) == 0) {
    283 		TRACE((MMS_DEBUG, "dm_proc_request: Resumed at position %lld",
    284 		    pos.lgclblkno));
    285 	}
    286 
    287 	wka->dm_request = NULL;		/* request done */
    288 	ioctl(wka->dm_drm_fd, DRM_RESUME, &rep);
    289 	TRACE((MMS_DEBUG, "Resume with rc = %lld", rep.drm_rep_rc));
    290 
    291 	if (req->drm_req_type == DRM_REQ_OPEN) {
    292 		if (rep.drm_rep_rc == 0) {
    293 			/* Opened successfully */
    294 			wka->dm_flags |= DM_OPENED;
    295 		}
    296 
    297 	}
    298 
    299 }
    300 
    301 int
    302 dm_ioctl_mtiocltop(drm_request_t *req, drm_reply_t *rep)
    303 {
    304 	drm_mtop_t	*op = &req->drm_mtop_req;
    305 	int		rc = 0;
    306 
    307 	rep->drm_mtop_rep.drm_op = op->drm_op;
    308 	rep->drm_mtop_rep.drm_count = op->drm_count;
    309 
    310 	switch (op->drm_op) {
    311 	case MTREW:
    312 	case MTRETEN:
    313 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTREW/MTRETEN"));
    314 		rc = dm_ioctl_rewind();
    315 		break;
    316 	case MTSEEK:
    317 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTSEEK"));
    318 		rc = dm_ioctl_seek(op->drm_count);
    319 		break;
    320 	case MTTELL:
    321 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTTELL"));
    322 		drv->drv_flags &= ~DRV_VALID_STAT;
    323 		rc = DRV_CALL(drv_tell,
    324 		    ((uint64_t *)&rep->drm_mtop_rep.drm_count));
    325 		if (rc) {
    326 			DM_MSG_SEND((DM_ADM_ERR, DM_6523_MSG, DM_MSG_REASON));
    327 		}
    328 		break;
    329 	case MTFSF:
    330 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTFSF"));
    331 		rc = dm_ioctl_fsf(op->drm_count);
    332 		break;
    333 	case MTFSR:
    334 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTFSR"));
    335 		rc = dm_ioctl_fsb(op->drm_count);
    336 		break;
    337 	case MTBSF:
    338 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTBSF"));
    339 		rc = dm_ioctl_bsf(op->drm_count);
    340 		break;
    341 	case MTBSR:
    342 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTBSR"));
    343 		rc = dm_ioctl_bsb(op->drm_count);
    344 		break;
    345 	case MTWEOF:
    346 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTWEOF"));
    347 		rc = dm_ioctl_wtm(op->drm_count);
    348 		break;
    349 	case MTEOM:
    350 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTEOM"));
    351 		rc = dm_goto_eof();
    352 		break;
    353 	case MTSRSZ:
    354 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTSRSZ"));
    355 		/*
    356 		 * You're allowed to set any record size any time.
    357 		 */
    358 		rc = dm_ioctl_set_blksize(op->drm_count);
    359 		break;
    360 	case MTGRSZ:
    361 		TRACE((MMS_INFO, "dm_ioctl_mtiocltop: MTGRSZ"));
    362 		if (drv->drv_flags & DRV_FATAL) {
    363 			rc = EIO;
    364 			break;
    365 		}
    366 		rc = DRV_CALL(drv_get_blksize,
    367 		    ((uint64_t *)&rep->drm_mtop_rep.drm_count));
    368 		if (rc) {
    369 			DM_MSG_SEND((DM_ADM_ERR, DM_6514_MSG, DM_MSG_REASON));
    370 		}
    371 		rep->drm_mtop_rep.drm_op = MTGRSZ;
    372 		break;
    373 
    374 	default:
    375 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    376 		    "0x%x", (int)op->drm_op));
    377 		DM_MSG_SEND((DM_ADM_ERR, DM_6515_MSG, DM_MSG_REASON));
    378 		rc = EINVAL;
    379 		break;
    380 	}
    381 
    382 	return (rc);
    383 }
    384 
    385 
    386 int
    387 dm_open(drm_request_t *req, drm_reply_t *rep)
    388 {
    389 	int		newfile = 0;
    390 	drm_open_t	*oreq = &req->drm_open_req;
    391 	tapepos_t	pos;
    392 	int		rc = 0;
    393 	char		*user;
    394 
    395 	TRACE((MMS_DEBUG, "dm_open: Enter dm_open"));
    396 
    397 	/*
    398 	 * Must be attached to open
    399 	 */
    400 	if ((drv->drv_flags & DRV_ATTACHED) == 0) {
    401 		/* Not attached */
    402 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    403 		    "Drive not attached"));
    404 		rc = ENODEV;
    405 		goto fatal;
    406 	}
    407 
    408 	if (wka->dm_hdl_minor != oreq->drm_open_minor) {
    409 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    410 		    "Target ID mismatch, requested %lld, have %d",
    411 		    oreq->drm_open_minor, wka->dm_hdl_minor));
    412 		rc = ENODEV;
    413 		goto fatal;
    414 	}
    415 
    416 	/* Return EBUSY if already opened */
    417 	if (wka->dm_app_pid) {
    418 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    419 		    "Already opened by pid = %d", wka->dm_app_pid));
    420 		rc = EBUSY;
    421 		goto fatal;
    422 	}
    423 
    424 	/*
    425 	 * Save application's pid and user name
    426 	 */
    427 	wka->dm_app_pid = req->drm_req_pid;
    428 	user = dm_get_user(req->drm_req_pid);
    429 	if (user == NULL) {
    430 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    431 		    "Unable to get user from uid %lld", req->drm_req_uid));
    432 		rc = EPERM;
    433 		goto fatal;
    434 	}
    435 
    436 	/*
    437 	 * Check user authentication
    438 	 */
    439 	if (dm_chk_dev_auth(user) != 0) {
    440 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    441 		    "User %s is not authorized to use MMS",
    442 		    user));
    443 		rc = EPERM;
    444 		goto fatal;
    445 	}
    446 
    447 
    448 	if ((drv->drv_flags & DRV_LOADED) == 0) {
    449 		/* Cartridge is not loaded */
    450 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    451 		    "Cartridge %s, Volume %s not loaded",
    452 		    mnt->mnt_pcl, mnt->mnt_volumename));
    453 		rc = ENOTTY;
    454 		goto fatal;
    455 	}
    456 
    457 	/*
    458 	 * Check MMS mode
    459 	 */
    460 	if ((mnt->mnt_flags & MNT_MMS) == 0) {
    461 		/* In raw mode */
    462 		TRACE((MMS_DEBUG, "dm_open: RAW mode"));
    463 		rc = ioctl(wka->dm_drm_fd, DRM_MMS_MODE, 0);
    464 		if (rc < 0) {
    465 			rc = errno;
    466 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    467 			    "Cannot set raw mode: %s", strerror(rc)));
    468 			goto fatal;
    469 		}
    470 
    471 		if (DRV_CALL(drv_bind_raw_dev,
    472 		    (req->drm_open_req.drm_open_flags | FNDELAY)) != 0) {
    473 			rc = errno;
    474 			DM_MSG_PREPEND(("Cannot set raw mode: %s: ",
    475 			    strerror(rc)));
    476 			goto fatal;
    477 		}
    478 		/* The entire tape is user data in non MMS mode */
    479 		drv->drv_flags |= DRV_UDATA;
    480 		drv->drv_numopens++;	/* 1 more open */
    481 		drv->drv_flags |= DRV_OPENED;
    482 		/*
    483 		 * Set the bit format
    484 		 */
    485 		if (dm_update_bitformat()) {
    486 			DM_MSG_PREPEND(("update bit format error: "));
    487 			rc = EIO;
    488 			goto fatal;
    489 		}
    490 
    491 		return (0);
    492 	}
    493 
    494 	/*
    495 	 * MMS mode
    496 	 */
    497 
    498 	/*
    499 	 * Save open flags
    500 	 */
    501 	drv->drv_oflags = oreq->drm_open_flags;
    502 
    503 	/*
    504 	 * Set readonly/readwrite flags
    505 	 */
    506 	if ((drv->drv_oflags & O_RDONLY) ||
    507 	    (mnt->mnt_flags & MNT_READONLY)) {
    508 		TRACE((MMS_DEBUG, "readonly open option"));
    509 		drv->drv_flags |= DRV_READONLY;
    510 	}
    511 
    512 	if (mnt->mnt_flags & MNT_READWRITE) {
    513 		if (drv->drv_flags & DRV_READONLY) {
    514 			TRACE((MMS_DEBUG, "dm_open: explicit readwrite "
    515 			    "on mount command overrides readonly option"));
    516 			drv->drv_flags &= ~DRV_READONLY;
    517 		}
    518 	}
    519 
    520 	if (drv->drv_flags & DRV_WRITEPROTECTED) {
    521 		TRACE((MMS_DEBUG, "dm_open: cartridge writeprotected"));
    522 		drv->drv_flags |= DRV_READONLY;
    523 	}
    524 
    525 	/*
    526 	 * Set disposition of file
    527 	 */
    528 	if ((drv->drv_oflags & FCREAT) || (mnt->mnt_flags & MNT_CREAT)) {
    529 		drv->drv_flags |= DRV_CREAT;
    530 	}
    531 
    532 	if (drv->drv_oflags & FAPPEND) {
    533 		drv->drv_flags |= DRV_APPEND;
    534 	}
    535 
    536 	/*
    537 	 * Save current tape position before validation. We may have to
    538 	 * return to this position if the rest of open fails.
    539 	 */
    540 	if (DRV_CALL(drv_get_pos, (&pos)) != 0) {
    541 		DM_MSG_PREPEND(("unable to get current position: "));
    542 		rc = EIO;
    543 		goto fatal;
    544 	}
    545 	drv->drv_cur_pos = pos;
    546 
    547 	/*
    548 	 * Determine if a new file should be created
    549 	 */
    550 	if (drv->drv_lbl_type != DRV_NL) {
    551 		rc = dm_open_labeled(&newfile);
    552 	} else {
    553 		rc = dm_open_nonlabeled(&newfile);
    554 	}
    555 	if (rc != 0) {
    556 		goto fatal;
    557 	}
    558 
    559 	if (newfile &&
    560 	    (drv->drv_flags & DRV_READONLY)) {
    561 		/* Readonly is for old only */
    562 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    563 		    "cannot write to readonly"));
    564 		rc = EACCES;
    565 		goto fatal;
    566 	}
    567 
    568 	/*
    569 	 * Set record format
    570 	 */
    571 	if (mnt->mnt_flags & MNT_FIXED) {
    572 		drv->drv_flags |= DRV_FIXED;
    573 		drv->drv_flags &= ~DRV_VARIABLE;
    574 	} else {
    575 		drv->drv_flags &= ~DRV_FIXED;
    576 		drv->drv_flags |= DRV_VARIABLE;
    577 	}
    578 
    579 	TRACE((MMS_DEBUG, "dm_open: %s, %s, %s, %s",
    580 	    drv->drv_flags & DRV_CREAT ? "CREAT" : "OLD",
    581 	    drv->drv_flags & DRV_READONLY ? "READONLY" : "READWRITE",
    582 	    drv->drv_flags & DRV_APPEND ? "APPEND" : "NOT_APPEND",
    583 	    drv->drv_flags & DRV_FIXED ? "FIXED" : "VARIABLE"));
    584 
    585 	if (newfile) {
    586 		/* Turn off append */
    587 		drv->drv_flags &= ~DRV_APPEND;
    588 
    589 		/*
    590 		 * Check expiration date.
    591 		 */
    592 		if (drv->drv_lbl_type != DRV_NL) {
    593 			if (dm_validate_xdate() != 0) {
    594 				DM_MSG_PREPEND(("Existing file not expired: "));
    595 				/* Existing file not expired */
    596 				rc = EACCES;
    597 				goto fatal;
    598 			}
    599 		}
    600 
    601 		if (dm_set_label_blksize() != 0) {
    602 			DM_MSG_PREPEND(("Set label blksize error: "));
    603 			rc = EIO;
    604 			goto fatal;
    605 		}
    606 		if (mnt->mnt_fseq == 1) {
    607 			/*
    608 			 * If mounted tape is NL, then decide whether to
    609 			 * write new label to AL.
    610 			 */
    611 			if (drv->drv_lbl_type == DRV_NL) {
    612 				if (dm_ask_write_lbl("NL", "AL",
    613 				    mnt->mnt_pcl) != 0) {
    614 					/* Don't write new label */
    615 					rc = EACCES;
    616 					goto fatal;
    617 				}
    618 			}
    619 			/*
    620 			 * If creating the first file, rewind
    621 			 * to BOM and set density and create
    622 			 * VOL1 again
    623 			 */
    624 			if (DRV_CALL(drv_rewind, ())) {
    625 				rc = EIO;
    626 				goto fatal;
    627 			}
    628 			if ((mnt->mnt_flags & MNT_AUTO_DEN) == 0) {
    629 				if (DRV_CALL(drv_set_density, (mnt->
    630 				    mnt_density->sym_code)) != 0) {
    631 					rc = EIO;
    632 					goto fatal;
    633 				}
    634 			}
    635 			if (dm_create_vol1() != 0) {
    636 				rc = EIO;
    637 				goto fatal;
    638 			}
    639 		} else {
    640 			/* fseq != 1 */
    641 			if (DRV_CALL(drv_locate, (&pos)) != 0) {
    642 				rc = EIO;
    643 				goto fatal;
    644 			}
    645 		}
    646 		/* Create file, write hdr label */
    647 		if (dm_create_hdr1() != 0) {
    648 			rc = EIO;
    649 			goto fatal;
    650 		}
    651 		if (dm_create_hdr2() != 0) {
    652 			rc = EIO;
    653 			goto fatal;
    654 		}
    655 		if (DRV_CALL(drv_wtm, (1)) != 0) {
    656 			rc = EIO;
    657 			goto fatal;
    658 		}
    659 		drv->drv_flags &= ~DRV_TM;
    660 		drv->drv_flags |=
    661 		    (DRV_TERM_FILE | DRV_BOF | DRV_UDATA |
    662 		    DRV_VALIDATED_FNAME);
    663 		if (dm_get_bof_pos() != 0) {
    664 			rc = EIO;
    665 			goto fatal;
    666 		}
    667 	}
    668 
    669 	if ((drv->drv_flags & DRV_VALIDATED_FNAME) == 0) {
    670 		/*
    671 		 * File must be validated by now
    672 		 */
    673 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    674 		    "Unable to validate filename"));
    675 		rc = EACCES;
    676 		goto fatal;
    677 	}
    678 
    679 	if ((drv->drv_flags & DRV_UDATA) == 0) {
    680 		/*
    681 		 * Validated and not in user data, then
    682 		 * position file to BOF
    683 		 */
    684 		if (DRV_CALL(drv_fsf, (1)) != 0) {
    685 			DM_MSG_PREPEND(("spacing to user data error: "));
    686 			rc = EIO;
    687 			goto fatal;
    688 		}
    689 		drv->drv_flags &= ~DRV_TM;
    690 		drv->drv_flags |= (DRV_BOF | DRV_UDATA);
    691 		if (dm_get_bof_pos() != 0) {
    692 			DM_MSG_PREPEND(("cannot get bof position: "));
    693 			rc = EIO;
    694 			goto fatal;
    695 		}
    696 	}
    697 
    698 	if ((drv->drv_flags & DRV_UDATA) == 0) {
    699 		/*
    700 		 * Must be in user data now
    701 		 */
    702 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    703 		    "Unable to reach user data in file"));
    704 		rc = EACCES;
    705 		goto fatal;
    706 	}
    707 
    708 	if ((drv->drv_flags & DRV_VALID_BOF_POS) == 0) {
    709 		/*
    710 		 * Must have BOF position
    711 		 */
    712 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    713 		    "Unable to get BOF position"));
    714 		rc = EACCES;
    715 		goto fatal;
    716 	}
    717 
    718 	/*
    719 	 * Get EOF position from MM
    720 	 */
    721 	if (newfile) {
    722 		drv->drv_flags &= ~DRV_VALID_EOF_POS;
    723 		drv->drv_flags |= DRV_UPDATE_EOF_POS;
    724 		/* ignore send error */
    725 		(void) dm_send_eof_pos();
    726 	} else if ((drv->drv_flags & DRV_VALID_EOF_POS) == 0) {
    727 		if (dm_show_eof_pos() != 0) {
    728 			drv->drv_flags &= ~DRV_VALID_EOF_POS;
    729 		}
    730 	}
    731 
    732 	/*
    733 	 * Position in the file
    734 	 */
    735 	if (newfile == 0) {
    736 		if (dm_open_pos() != 0) {
    737 			/* Error */
    738 			DM_MSG_PREPEND(("unable to reposition file: "));
    739 			rc = EIO;
    740 			goto fatal;
    741 		}
    742 	}
    743 
    744 	/*
    745 	 * Now that the file is positioned correctly, reset the disposition
    746 	 * so that open flags will be used.
    747 	 */
    748 	mnt->mnt_flags &= ~(MNT_CREAT | MNT_OLD);
    749 	drv->drv_flags &= ~DRV_CREAT;		/* and turn off create */
    750 
    751 	/*
    752 	 * Switch to user's file
    753 	 */
    754 	if (DRV_CALL(drv_bind_raw_dev,
    755 	    (req->drm_open_req.drm_open_flags | FNDELAY) != 0)) {
    756 		rc = errno;
    757 		DM_MSG_PREPEND(("Raw device open error: %s: ", strerror(rc)));
    758 		wka->dm_app_pid = 0;
    759 		goto fatal;
    760 	}
    761 	TRACE((MMS_DEBUG, "Opened by pid %d", (int)wka->dm_app_pid));
    762 
    763 	/*
    764 	 * Set up file blksize, density and compression
    765 	 */
    766 	if (dm_set_file_blksize(-1) != 0) {
    767 		/*
    768 		 * Rebind to target base
    769 		 */
    770 		DM_MSG_PREPEND(("set file blocksize error: "));
    771 		if (DRV_CALL(drv_rebind_target, ()) != 0) {
    772 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    773 			    "Rebind base device error: %s",
    774 			    strerror(errno)));
    775 		}
    776 		rc = EIO;
    777 		goto fatal;
    778 	}
    779 
    780 	/*
    781 	 * Set the bit format
    782 	 */
    783 	if (dm_update_bitformat() != 0) {
    784 		DM_MSG_PREPEND(("unable to update bit format: "));
    785 		rc = EIO;
    786 		goto fatal;
    787 	}
    788 	rep->drm_rep_flags |= (DRM_REP_NOTIFY_WRITE | DRM_REP_NOTIFY_READ);
    789 	if (rc == 0) {
    790 		/* Successfully positioned, turn off append */
    791 		drv->drv_flags &= ~DRV_APPEND;
    792 		drv->drv_flags |= DRV_OPENED;
    793 	}
    794 	free(user);
    795 	return (rc);
    796 
    797 fatal:
    798 	free(user);
    799 	wka->dm_app_pid = 0;
    800 	DRV_CALL(drv_locate, (&pos));
    801 	DM_MSG_SEND((DM_ADM_ERR, DM_6516_MSG, DM_MSG_REASON));
    802 	(void) dm_set_label_blksize();
    803 	return (rc);
    804 
    805 }
    806 
    807 int
    808 dm_open_labeled(int *newfile)
    809 {
    810 	/*
    811 	 * Position to the file seq
    812 	 */
    813 	if (dm_pos_fseq() != 0) {
    814 		return (EIO);
    815 	}
    816 
    817 	if (drv->drv_fseq != mnt->mnt_fseq) {
    818 		/*
    819 		 * We must be at the file requested by the user
    820 		 */
    821 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    822 		    "Unable to reach requested file"));
    823 		return (EIO);
    824 	}
    825 
    826 	/*
    827 	 * Determine if a new file will be created
    828 	 */
    829 
    830 	*newfile = 0;
    831 	if (drv->drv_flags & DRV_CREAT) {
    832 		/*
    833 		 * Create a new file
    834 		 */
    835 		*newfile = 1;
    836 		if (drv->drv_flags & DRV_UDATA) {
    837 			if (drv->drv_fseq == 1) {
    838 				if (DRV_CALL(drv_rewind, ()) != 0 ||
    839 				    DRV_CALL(drv_fsb, (1,
    840 				    DRV_LOGICAL_CROSS_TM)) != 0) {
    841 					DM_MSG_PREPEND(("unable to "
    842 					    "position cartridge: "));
    843 					return (EIO);
    844 				}
    845 			} else {
    846 				if (dm_rewind_file() != 0 ||
    847 				    DRV_CALL(drv_bsf, (2)) != 0 ||
    848 				    DRV_CALL(drv_fsf, (1)) != 0) {
    849 					DM_MSG_PREPEND(("unable to "
    850 					    "position cartridge: "));
    851 					return (EIO);
    852 				}
    853 			}
    854 			drv->drv_flags &= ~DRV_UDATA;
    855 		}
    856 		if ((drv->drv_flags & DRV_VALIDATED_FNAME) != 0) {
    857 			if (dm_validate_fname() != 0) {
    858 				return (ENOENT);
    859 			}
    860 		}
    861 		drv->drv_flags |= DRV_VALIDATED_FNAME;
    862 	} else {
    863 		/*
    864 		 * Writing over an existing file
    865 		 */
    866 		if ((drv->drv_flags & DRV_UDATA) == 0) {
    867 			/* Not in user data and validate filename */
    868 			if ((drv->drv_flags & DRV_VALIDATED_FNAME) == 0) {
    869 				if (dm_validate_fname() != 0) {
    870 					return (EACCES);
    871 				}
    872 			}
    873 		}
    874 	}
    875 
    876 	/*
    877 	 * Set up blocksize
    878 	 */
    879 	if (drv->drv_flags & DRV_CREAT) {
    880 		drv->drv_file_blksize = mnt->mnt_blksize > 0 ?
    881 		    mnt->mnt_blksize : drv->drv_dflt_blksize;
    882 	} else {
    883 		drv->drv_file_blksize = mnt->mnt_blksize > 0 ?
    884 		    mnt->mnt_blksize : drv->drv_lbl_blksize;
    885 	}
    886 	return (0);
    887 }
    888 
    889 int
    890 dm_open_nonlabeled(int *newfile)
    891 {
    892 	/*
    893 	 * Mounted cartridge is NL
    894 	 * If mount option is AL, then create label if not done already
    895 	 */
    896 	if (mnt->mnt_lbl_type == DRV_AL && (drv->drv_flags & DRV_BOM)) {
    897 		/* Can only create fseq 1 */
    898 		if (mnt->mnt_fseq > 1) {
    899 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    900 			    "Do not support fseq = %d", mnt->mnt_fseq));
    901 			return (ENOENT);
    902 		}
    903 		/*
    904 		 * Must create a new file
    905 		 */
    906 		*newfile = 1;
    907 
    908 		/*
    909 		 * Set up blocksize
    910 		 */
    911 		drv->drv_file_blksize = mnt->mnt_blksize > 0 ?
    912 		    mnt->mnt_blksize : drv->drv_dflt_blksize;
    913 	}
    914 
    915 	return (0);
    916 }
    917 
    918 int
    919 dm_validate_xdate(void)
    920 {
    921 	time_t		curtime;
    922 	int		curdate;
    923 	int		xdate;
    924 	int		tmp;
    925 	int		i;
    926 	char		lxdate[7];
    927 	struct		tm tm;
    928 
    929 	if (mnt->mnt_lbl_type == DRV_NL) {
    930 		/* nonlabeled */
    931 		return (0);
    932 	}
    933 
    934 	strncpy(lxdate, drv->drv_hdr1.hdr1_xdate, 6);
    935 	lxdate[6] = '\0';
    936 	if (strncmp(lxdate + 1, "00000", 5) == 0) {
    937 		/* No expiration date used */
    938 		return (0);
    939 	}
    940 
    941 	/*
    942 	 * If date is invalid, then ignore
    943 	 */
    944 	if (lxdate[0] != ' ' && lxdate[0] != '0') {
    945 		goto invalid_xdate;
    946 	}
    947 	for (i = 0; i < 5; i++) {
    948 		if (!isdigit(lxdate[1 + i])) {
    949 			goto invalid_xdate;
    950 		}
    951 	}
    952 	sscanf(lxdate + 3, "%d", &tmp);
    953 	if (tmp < 1 || tmp > 366) {
    954 		goto invalid_xdate;
    955 	}
    956 
    957 	if ((drv->drv_flags & DRV_VALIDATE_XDATE) == 0) {
    958 		/* Don't validate expiration date */
    959 		return (0);
    960 	}
    961 
    962 	/*
    963 	 * Get expiration date since 1900
    964 	 */
    965 	sscanf(lxdate + 1, "%d", &xdate);
    966 	if (lxdate[0] == '0') {
    967 		/* years since 1900 */
    968 		xdate += 100000;
    969 	}
    970 
    971 	/*
    972 	 * Get current date since 1900
    973 	 */
    974 	curtime = time(NULL);
    975 	localtime_r(&curtime, &tm);
    976 	curdate = tm.tm_year * 1000 + tm.tm_yday + 1;
    977 
    978 	if (xdate > curdate) {
    979 		/* file not expired */
    980 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
    981 		    "Existing file not expired: "
    982 		    "expiration date = %s", lxdate));
    983 		return (-1);
    984 	} else {
    985 		/* File expired */
    986 		return (0);
    987 	}
    988 
    989 invalid_xdate:
    990 	TRACE((MMS_DEBUG, "invalid expiration date: %s", lxdate));
    991 	return (0);
    992 }
    993 
    994 /*
    995  * Currently, only one file is supported on each volume, so fseq can only be 1.
    996  */
    997 
    998 int
    999 dm_pos_fseq(void)
   1000 {
   1001 	if (drv->drv_fseq == 0) {
   1002 		/* Tape not positioned */
   1003 		if (DRV_CALL(drv_rewind, ()) != 0) {
   1004 			return (EIO);
   1005 		}
   1006 		if (drv->drv_lbl_type != DRV_NL) {
   1007 			if (DRV_CALL(drv_fsb, (1, DRV_LOGICAL_CROSS_TM))) {
   1008 				return (EIO);
   1009 			}
   1010 		}
   1011 		drv->drv_flags &= ~(DRV_UDATA | DRV_BOF |
   1012 		    DRV_EOF | DRV_TM | DRV_HDR1 |
   1013 		    DRV_HDR2 | DRV_EOF1 | DRV_EOF2);
   1014 		drv->drv_fseq = 1;
   1015 	}
   1016 
   1017 	if (mnt->mnt_fseq == drv->drv_fseq) {
   1018 		/* Already positioned to file */
   1019 		return (0);
   1020 	}
   1021 
   1022 	/*
   1023 	 * We don't support fseq > 1 for the time being
   1024 	 */
   1025 	if (mnt->mnt_fseq > 1) {
   1026 		return (EINVAL);
   1027 	}
   1028 
   1029 	return (0);
   1030 }
   1031 
   1032 int
   1033 dm_get_bof_pos(void)
   1034 {
   1035 	if ((drv->drv_flags & DRV_BOF) == 0) {
   1036 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1037 		    "Not at BOF. Can't get BOF position"));
   1038 		return (EACCES);
   1039 	}
   1040 
   1041 	if (DRV_CALL(drv_get_pos, (&drv->drv_bof_pos)) != 0) {
   1042 		return (EIO);
   1043 	}
   1044 	drv->drv_flags |= DRV_VALID_BOF_POS;
   1045 	return (0);
   1046 }
   1047 
   1048 int
   1049 dm_get_eof_pos(void)
   1050 {
   1051 	if ((drv->drv_flags & DRV_EOF) == 0) {
   1052 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1053 		    "not at EOF. cannot get EOF position"));
   1054 		return (EACCES);
   1055 	}
   1056 
   1057 	if (DRV_CALL(drv_get_pos, (&drv->drv_eof_pos)) != 0) {
   1058 		return (EIO);
   1059 	}
   1060 	drv->drv_flags |= DRV_VALID_EOF_POS;
   1061 	drv->drv_cur_pos = drv->drv_eof_pos;
   1062 	return (0);
   1063 }
   1064 
   1065 int
   1066 dm_open_pos(void)
   1067 {
   1068 	if ((drv->drv_flags & DRV_UDATA) == 0) {
   1069 		/*
   1070 		 * Must be in uset data to do positioning at open
   1071 		 */
   1072 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1073 		    "Not in user data. Can't do open position"));
   1074 		return (EACCES);
   1075 	}
   1076 
   1077 	if ((drv->drv_flags & DRV_VALID_BOF_POS) == 0) {
   1078 		/*
   1079 		 * Must have BOF position
   1080 		 */
   1081 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1082 		    "Don't have BOF position. " "Can't do open position"));
   1083 		return (EACCES);
   1084 	}
   1085 
   1086 	if (drv->drv_flags & DRV_CREAT) {
   1087 		if (DRV_CALL(drv_locate, (&drv->drv_bof_pos)) != 0) {
   1088 			return (EIO);
   1089 		}
   1090 		drv->drv_cur_pos = drv->drv_bof_pos;
   1091 	} else if (drv->drv_flags & DRV_APPEND) {
   1092 		/* Go to eof */
   1093 		return (dm_goto_eof());
   1094 	}
   1095 	return (0);
   1096 }
   1097 
   1098 int
   1099 dm_goto_eof(void)
   1100 {
   1101 	char		buf[80] = "";
   1102 	int		rc;
   1103 	tapepos_t	cur_pos = drv->drv_cur_pos;
   1104 
   1105 	if (drv->drv_flags & DRV_FATAL) {
   1106 		return (EIO);
   1107 	}
   1108 
   1109 	if ((drv->drv_flags & DRV_UDATA) == 0) {
   1110 		/*
   1111 		 * Must be in user data to go to EOF
   1112 		 */
   1113 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1114 		    "Not in user data. Can't go to EOF"));
   1115 		return (EACCES);
   1116 	}
   1117 
   1118 	if (DRV_CALL(drv_get_pos, (&cur_pos)) != 0) {
   1119 		return (EIO);
   1120 	}
   1121 	drv->drv_flags &= ~(DRV_TM | DRV_EOF);
   1122 
   1123 	/*
   1124 	 * If eof position is valid, then locate to it
   1125 	 */
   1126 	if (dm_set_label_blksize()) {
   1127 		return (EIO);
   1128 	}
   1129 	if (drv->drv_flags & DRV_VALID_EOF_POS) {
   1130 		if (DRV_CALL(drv_locate, (&drv->drv_eof_pos)) != 0) {
   1131 			goto repos;
   1132 		}
   1133 		drv->drv_cur_pos = drv->drv_eof_pos;
   1134 		/*
   1135 		 * If this is really EOF, then the next block must be a
   1136 		 * tapemark followed by the trailor label.
   1137 		 */
   1138 		if (DRV_CALL(drv_fsb, (1, DRV_LOGICAL_CROSS_TM)) != 0) {
   1139 			/* Could not space 1 block */
   1140 			/* We're at EOF if we hit EOM or blank check */
   1141 			drv->drv_flags &= ~DRV_VALID_STAT;
   1142 			if (serr->se_senkey == SUN_KEY_EOT ||
   1143 			    serr->se_senkey == KEY_BLANK_CHECK) {
   1144 				TRACE((MMS_DEBUG, "Hit EOT/BLANK CHECK"));
   1145 				goto done;
   1146 			}
   1147 			/*
   1148 			 * Hit a tapemark, read the next block to see if it is a
   1149 			 * trailor label.
   1150 			 */
   1151 			if ((drv->drv_flags & DRV_TM) != 0) {
   1152 				if (DRV_CALL(drv_read, (buf, 80)) != 80) {
   1153 					/*
   1154 					 * We're at EOF if we hit EOM or
   1155 					 * blank check
   1156 					 */
   1157 					if (serr->se_senkey == SUN_KEY_EOT ||
   1158 					    serr->se_senkey ==
   1159 					    KEY_BLANK_CHECK) {
   1160 						TRACE((MMS_DEBUG,
   1161 						    "Hit EOT/BLANK CHECK"));
   1162 						drv->drv_flags &=
   1163 						    ~DRV_VALID_EOF_POS;
   1164 						goto done;
   1165 					} else {
   1166 						/* other error */
   1167 						goto repos;
   1168 					}
   1169 				}
   1170 				/*
   1171 				 * Read an 80 byte record
   1172 				 */
   1173 				if (dm_verify_trailor_label(buf) == 0) {
   1174 					TRACE((MMS_DEBUG, "Found EOF"));
   1175 					if (DRV_CALL(drv_locate,
   1176 					    (&drv->drv_eof_pos)) != 0) {
   1177 						/*
   1178 						 * Can't reposition
   1179 						 * to EOF
   1180 						 */
   1181 						goto repos;
   1182 					}
   1183 					drv->drv_cur_pos = drv->drv_eof_pos;
   1184 					goto done;
   1185 				}
   1186 			} else {
   1187 				/* All errors, do it the hard way */
   1188 				goto repos;
   1189 			}
   1190 		} else {
   1191 			/* Skipped a block, this is not EOF for sure */
   1192 			goto repos;
   1193 		}
   1194 repos:
   1195 		/*
   1196 		 * Don't find trailor label.
   1197 		 * Return to where we started and try to locate EOF
   1198 		 * the hard way.
   1199 		 */
   1200 		if (dm_set_file_blksize(drv->drv_cur_blksize)) {
   1201 			return (EIO);
   1202 		}
   1203 		drv->drv_flags &= ~DRV_VALID_EOF_POS;
   1204 		buf[0] = '\0';
   1205 		if (DRV_CALL(drv_locate, (&cur_pos)) != 0) {
   1206 			return (EIO);
   1207 		}
   1208 		drv->drv_cur_pos = cur_pos;
   1209 		drv->drv_flags &= ~(DRV_TM | DRV_EOF);
   1210 	}
   1211 
   1212 	/*
   1213 	 * Eof position is not valid, find eof the hard way
   1214 	 */
   1215 
   1216 	if (dm_set_label_blksize()) {
   1217 		return (EIO);
   1218 	}
   1219 	for (;;) {
   1220 		if (DRV_CALL(drv_fsf, (1)) != 0) {
   1221 			/* We're at EOF if we hit EOM or blank check */
   1222 			if (serr->se_senkey == SUN_KEY_EOT ||
   1223 			    serr->se_senkey == KEY_BLANK_CHECK) {
   1224 				TRACE((MMS_DEBUG, "Hit EOT/BLANK CHECK"));
   1225 				goto done;
   1226 			}
   1227 			goto err;
   1228 		}
   1229 		/*
   1230 		 * Try to read the next block to see if it is a trailor label.
   1231 		 * Skip over any tapemark we encounter
   1232 		 */
   1233 		while ((rc = DRV_CALL(drv_read, (buf, 80))) != 80) {
   1234 			/* We're at EOF if we hit EOM or blank check */
   1235 			if (serr->se_senkey == SUN_KEY_EOT ||
   1236 			    serr->se_senkey == KEY_BLANK_CHECK) {
   1237 				TRACE((MMS_DEBUG, "Hit EOT/BLANK CHECK"));
   1238 				drv->drv_flags |= DRV_EOF;
   1239 				DRV_CALL(drv_clrerr, ());
   1240 				goto done;
   1241 			} else if (drv->drv_flags & DRV_TM) {
   1242 				/* Hit a tapemark */
   1243 				continue;	/* Check for eof label */
   1244 			} else if (rc > 0) {
   1245 				/* Read a short block */
   1246 				continue;
   1247 			} else {
   1248 				/* other error */
   1249 				goto err;
   1250 			}
   1251 		}
   1252 		if (rc != 80) {
   1253 			/* Read a short block */
   1254 			continue;
   1255 		}
   1256 		/*
   1257 		 * Read an 80 byte record
   1258 		 */
   1259 		if (strncmp(buf, "EOF1", 4) == 0 ||
   1260 		    strncmp(buf, "EOV1", 4) == 0) {
   1261 			if (dm_verify_trailor_label(buf) != 0) {
   1262 				/* Invalid label structure */
   1263 				TRACE((MMS_ERR, "Invalid trailor label"));
   1264 				errno = EINVAL;
   1265 				goto err;
   1266 			}
   1267 			/* Found the EOF/EOV label */
   1268 			TRACE((MMS_DEBUG, "Found EOF"));
   1269 			break;
   1270 		}
   1271 	}
   1272 	/*
   1273 	 * We've read a trailor label. Position to the end of user data.
   1274 	 */
   1275 	if (DRV_CALL(drv_bsf, (1)) != 0) {
   1276 		goto err;
   1277 	}
   1278 
   1279 done:
   1280 	drv->drv_flags &= ~DRV_TM;
   1281 	drv->drv_flags |= DRV_EOF;
   1282 	if (dm_set_file_blksize(drv->drv_cur_blksize)) {
   1283 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1284 		    "Set file blksize error"));
   1285 		goto err;
   1286 	}
   1287 
   1288 	if ((drv->drv_flags & DRV_VALID_EOF_POS) == 0) {
   1289 		if (dm_get_eof_pos()) {
   1290 			TRACE((MMS_DEBUG, "Can't get EOF pos"));
   1291 			goto err;
   1292 		}
   1293 		drv->drv_flags |= DRV_UPDATE_EOF_POS;
   1294 	}
   1295 	return (0);
   1296 
   1297 err:
   1298 	/*
   1299 	 * Error going to EOF, reposition to where we started and return error
   1300 	 */
   1301 	DRV_CALL(drv_clrerr, ());
   1302 	DRV_CALL(drv_locate, (&cur_pos));
   1303 	if (dm_set_file_blksize(drv->drv_cur_blksize)) {
   1304 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1305 		    "Set file blksize error"));
   1306 	}
   1307 	return (EIO);
   1308 }
   1309 
   1310 int
   1311 dm_verify_trailor_label(char *buf)
   1312 {
   1313 	drv_eof1_t	*eof1 = (drv_eof1_t *)buf;
   1314 	drv_eov1_t	*eov1 = (drv_eov1_t *)buf;
   1315 	drv_hdr1_t	*hdr1 = &drv->drv_hdr1;
   1316 
   1317 	if (strncmp(eof1->eof1_id, "EOF1", 4) == 0) {
   1318 		if (strncmp(eof1->eof1_fseq, hdr1->hdr1_fseq, 4)) {
   1319 			/*
   1320 			 * EOF1 does not match HDR1
   1321 			 */
   1322 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1323 			    "EOF1 label does not match HDR1 label"));
   1324 			return (-1);
   1325 		}
   1326 	} else if (strncmp(eov1->eov1_id, "EOV1", 4) == 0) {
   1327 		if (strncmp(eov1->eov1_fseq, hdr1->hdr1_fseq, 4)) {
   1328 			/*
   1329 			 * EOV1 does not match HDR1
   1330 			 */
   1331 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1332 			    "EOV1 label does not match HDR1 label"));
   1333 			return (-1);
   1334 		}
   1335 	}
   1336 
   1337 	return (0);
   1338 }
   1339 
   1340 int
   1341 dm_chk_eof(void)
   1342 {
   1343 	int		rc;
   1344 	char		buf[80] = "";
   1345 	tapepos_t	pos;
   1346 
   1347 	if (DRV_CALL(drv_get_pos, (&pos)) != 0) {
   1348 		return (EIO);
   1349 	}
   1350 
   1351 	if ((rc = DRV_CALL(drv_read, (buf, 80))) <= 0) {
   1352 		/* We're at EOF if we hit EOM or blank check */
   1353 		if (serr->se_senkey == SUN_KEY_EOT ||
   1354 		    serr->se_senkey == KEY_BLANK_CHECK) {
   1355 			TRACE((MMS_DEBUG, "Hit EOT/BLANK CHECK"));
   1356 			drv->drv_flags |= DRV_EOF;
   1357 			if (dm_get_eof_pos()) {
   1358 				rc = EIO;
   1359 			} else {
   1360 				rc = 0;
   1361 			}
   1362 		} else {
   1363 			/* Other error */
   1364 			DRV_CALL(drv_clrerr, ());
   1365 			rc = EIO;
   1366 		}
   1367 	} else if (rc >= 80 &&
   1368 	    (strncmp(buf, "EOF1", 4) == 0 || strncmp(buf, "EOV1", 4) == 0)) {
   1369 		TRACE((MMS_DEBUG, "Found EOF1/EOV1"));
   1370 		rc = 0;
   1371 	}
   1372 
   1373 	DRV_CALL(drv_locate, (&pos));
   1374 	return (rc);
   1375 }
   1376 
   1377 int
   1378 dm_validate_fname(void)
   1379 {
   1380 	int		rc;
   1381 	drv_hdr1_t	*hdr1 = &drv->drv_hdr1;
   1382 	drv_hdr2_t	*hdr2 = &drv->drv_hdr2;
   1383 	char		tmp[18];
   1384 
   1385 	drv->drv_flags &= ~DRV_FIXED;	/* assume variable */
   1386 	drv->drv_flags |= DRV_VARIABLE;
   1387 	drv->drv_file_blksize = drv->drv_dflt_blksize;	/* default blksize */
   1388 
   1389 	if ((drv->drv_flags & DRV_HDR1) == 0) {
   1390 		rc = DRV_CALL(drv_read, ((char *)&drv->drv_hdr1, 80));
   1391 		if (rc != 80 ||
   1392 		    strncmp(drv->drv_hdr1.hdr1_id, "HDR1", 4) != 0) {
   1393 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1394 			    "invalid header label structure, no HDR1"));
   1395 			return (EINVAL);
   1396 		}
   1397 		drv->drv_flags |= DRV_HDR1;
   1398 
   1399 		strncpy(drv->drv_fid, drv->drv_hdr1.hdr1_fid, 17);
   1400 		drv->drv_fid[17] = '\0';
   1401 	}
   1402 
   1403 	/*
   1404 	 * Validate filename
   1405 	 */
   1406 	if (drv->drv_flags & DRV_VALIDATE_FNAME) {
   1407 		/* validate filename */
   1408 		if (strncmp(drv->drv_hdr1.hdr1_fid, mnt->mnt_fname, 17) != 0) {
   1409 			/* Mismatch filename */
   1410 			strncpy(tmp, drv->drv_hdr1.hdr1_fid, 17);
   1411 			tmp[17] = '\0';
   1412 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1413 			    "filename mismatch: "
   1414 			    "label %s, specified %s", tmp, mnt->mnt_fname));
   1415 		} else {
   1416 			/* File verified */
   1417 			drv->drv_flags |= DRV_VALIDATED_FNAME;
   1418 		}
   1419 	} else {
   1420 		/* File verified */
   1421 		drv->drv_flags |= DRV_VALIDATED_FNAME;
   1422 	}
   1423 
   1424 	/*
   1425 	 * HDR2 is optional
   1426 	 */
   1427 	if ((drv->drv_flags & DRV_HDR2) == 0) {
   1428 		rc = DRV_CALL(drv_read, ((char *)&drv->drv_hdr2, 80));
   1429 
   1430 		/*
   1431 		 * HDR2 optional. If no HDR2, then there must be a tapemark.
   1432 		 */
   1433 		if ((drv->drv_flags & DRV_TM) != 0) {
   1434 			TRACE((MMS_DEBUG, "No HDR2"));
   1435 			return (0);
   1436 		}
   1437 
   1438 		if (rc != 80 ||
   1439 		    strncmp(drv->drv_hdr2.hdr2_id, "HDR2", 4) != 0) {
   1440 			DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1441 			    "invalid header label structure, "
   1442 			    "invalid HDR2"));
   1443 			return (EIO);
   1444 		}
   1445 
   1446 		drv->drv_flags |= DRV_HDR2;
   1447 
   1448 		if (hdr2->hdr2_rformat == 'F') {
   1449 			drv->drv_flags |= DRV_FIXED;
   1450 			drv->drv_flags &= ~DRV_VARIABLE;
   1451 		} else {
   1452 			drv->drv_flags &= ~DRV_FIXED;
   1453 			drv->drv_flags |= DRV_VARIABLE;
   1454 		}
   1455 
   1456 		if (strncmp(hdr1->hdr1_impid, DRV_IMPID, DRV_IMPID_LEN) == 0 ||
   1457 		    strncmp(hdr1->hdr1_impid, DRV_IMPID2, DRV_IMPID_LEN) == 0) {
   1458 			/* Label created by MMS */
   1459 			strncpy(tmp, hdr2->hdr2_blksize,
   1460 			    sizeof (hdr2->hdr2_blksize));
   1461 			tmp[sizeof (hdr2->hdr2_blksize)] = '\0';
   1462 			sscanf(tmp, "%d", &drv->drv_lbl_blksize);
   1463 		} else {
   1464 			/* Label not created by MMS */
   1465 			strncpy(tmp, hdr2->hdr2_blklen, 5);
   1466 			tmp[5] = '\0';
   1467 			sscanf(tmp, "%d", &drv->drv_lbl_blksize);
   1468 			if (drv->drv_lbl_blksize >= 99999) {
   1469 				drv->drv_lbl_blksize = drv->drv_dflt_blksize;
   1470 			}
   1471 		}
   1472 	}
   1473 	return (0);
   1474 }
   1475 
   1476 
   1477 int
   1478 dm_close(void)
   1479 {
   1480 	TRACE((MMS_DEBUG, "Closing file"));
   1481 
   1482 	/*
   1483 	 * In MMS mode, terminate the tape if necessary
   1484 	 */
   1485 	if (mnt->mnt_flags & MNT_MMS) {
   1486 		if (drv->drv_flags & DRV_UDATA) {
   1487 			if (drv->drv_flags & DRV_TERM_FILE) {
   1488 				drv->drv_flags |= DRV_EOF;
   1489 				if (drv->drv_flags & DRV_UPDATE_EOF_POS) {
   1490 					(void) dm_get_eof_pos();
   1491 				}
   1492 				/*
   1493 				 * Ignore error since there isn't anything
   1494 				 * we can do except get it recorded.
   1495 				 */
   1496 				(void) dm_terminate_file();
   1497 				drv->drv_flags &= ~DRV_TERM_FILE;
   1498 			}
   1499 			if ((mnt->mnt_flags & MNT_NOREWIND) == 0) {
   1500 				/* Rewind at close */
   1501 				TRACE((MMS_DEBUG, "Rewind on close"));
   1502 				DRV_CALL(drv_locate, (&drv->drv_bof_pos));
   1503 				drv->drv_cur_pos = drv->drv_bof_pos;
   1504 			}
   1505 		}
   1506 	}
   1507 
   1508 	/*
   1509 	 * Rebind to target base
   1510 	 */
   1511 	if (DRV_CALL(drv_rebind_target, ()) != 0) {
   1512 		TRACE((MMS_ERR, "Rebind base device error: %s",
   1513 		    strerror(errno)));
   1514 		drv->drv_flags |= DRV_FATAL;
   1515 		TRACE((MMS_DEBUG, "FATAL error"));
   1516 	}
   1517 	dm_clear_dev();
   1518 
   1519 	ioctl(wka->dm_drm_fd, DRM_MMS_MODE, 1);
   1520 	if (drv->drv_flags & DRV_UPDATE_EOF_POS) {
   1521 		wka->dm_flags |= DM_SEND_EOF_POS;
   1522 		drv->drv_flags &= ~DRV_UPDATE_EOF_POS;
   1523 	}
   1524 	if (drv->drv_flags & DRV_UPDATE_CAPACITY) {
   1525 		wka->dm_flags |= DM_SEND_CAPACITY;
   1526 		drv->drv_flags &= ~DRV_UPDATE_CAPACITY;
   1527 	}
   1528 	wka->dm_app_pid = 0;
   1529 	TRACE((MMS_DEBUG, "Closed by pid %d", (int)wka->dm_app_pid));
   1530 	drv->drv_flags &= ~DRV_OPENED;
   1531 	pthread_mutex_lock(&wka->dm_worker_mutex);
   1532 	wka->dm_work_todo = 1;
   1533 	pthread_cond_broadcast(&wka->dm_work_cv);
   1534 	pthread_mutex_unlock(&wka->dm_worker_mutex);
   1535 	return (0);
   1536 }
   1537 
   1538 /*
   1539  * Terminate a acrtridge by writing either two tapemarks or trailor labels
   1540  */
   1541 int
   1542 dm_terminate_file(void)
   1543 {
   1544 	tapepos_t	pos;
   1545 	int		rc = 0;
   1546 	int		i;
   1547 
   1548 	/*
   1549 	 * At EOF now
   1550 	 */
   1551 	drv->drv_flags |= DRV_EOF;
   1552 
   1553 	if ((drv->drv_flags & DRV_UDATA) == 0) {
   1554 		/*
   1555 		 * Must be in user data to terminate file
   1556 		 */
   1557 		TRACE((MMS_ERR, "Not in user data. Can't terminate file"));
   1558 		return (EACCES);
   1559 	}
   1560 
   1561 	if ((drv->drv_flags & DRV_TERM_FILE) == 0) {
   1562 		/*
   1563 		 * Must have set DRV_TERM_FILE to terminate a file
   1564 		 */
   1565 		TRACE((MMS_ERR,
   1566 		    "DRV_TERM_FILE not set. Can't terminate file"));
   1567 	}
   1568 
   1569 	/*
   1570 	 * Save EOF pos
   1571 	 */
   1572 	(void) dm_get_eof_pos();
   1573 
   1574 	/*
   1575 	 * Save capacity of cartridge
   1576 	 */
   1577 	drv->drv_avail = DRV_CALL(drv_get_avail_capacity, ());
   1578 	drv->drv_pc_avail = (drv->drv_avail * 100) / drv->drv_capacity;
   1579 	drv->drv_flags |= DRV_UPDATE_CAPACITY;
   1580 
   1581 	if (DRV_CALL(drv_get_pos, (&pos)) != 0) {
   1582 		TRACE((MMS_ERR, "Can't read position"));
   1583 		return (EIO);
   1584 	}
   1585 
   1586 	ioctl(drv->drv_fd, MTIOCLRERR, 0);	/* clear outstanding error */
   1587 	if (drv->drv_lbl_type == DRV_NL) {
   1588 		/* write 2 tapemarks to terminate a NL tape */
   1589 		for (i = 0; i < 2; i++) {
   1590 			if (DRV_CALL(drv_wtm, (2)) != 0) {
   1591 				DRV_CALL(drv_clrerr, ());
   1592 				continue;
   1593 			}
   1594 			break;
   1595 		}
   1596 		if (i == 2) {
   1597 			TRACE((MMS_ERR, "Can't terminate cartridge"));
   1598 			rc = EIO;
   1599 		}
   1600 	} else {
   1601 		/*
   1602 		 * Write EOF/EOV labels
   1603 		 */
   1604 		rc = dm_create_trailor_lbls();
   1605 	}
   1606 
   1607 	/*
   1608 	 * Reposition to the end of user data
   1609 	 */
   1610 	if (rc != 0) {
   1611 		DRV_CALL(drv_clrerr, ());
   1612 	}
   1613 	if (DRV_CALL(drv_locate, (&drv->drv_eof_pos)) != 0) {
   1614 		TRACE((MMS_ERR, "Can't reposition to EOF"));
   1615 		rc = EIO;
   1616 	}
   1617 	if (dm_set_file_blksize(drv->drv_cur_blksize)) {
   1618 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1619 		    "Set file blksize error"));
   1620 		rc = EIO;
   1621 	}
   1622 	drv->drv_flags &= ~DRV_TM;
   1623 	drv->drv_cur_pos = drv->drv_eof_pos;
   1624 	if (rc == 0) {
   1625 		/*
   1626 		 * Successfully wrote trailor labels and return to end of
   1627 		 * user data. We'er at EOF.
   1628 		 */
   1629 		drv->drv_flags |= DRV_EOF;
   1630 	}
   1631 
   1632 	return (rc);
   1633 }
   1634 
   1635 int
   1636 dm_create_trailor_lbls(void)
   1637 {
   1638 	int		i;
   1639 
   1640 	for (i = 0; i < 2; i++) {
   1641 		if (DRV_CALL(drv_wtm, (1)) != 0) {
   1642 			if (serr->se_status == SUN_KEY_EOT &&
   1643 			    serr->se_resid == 1) {
   1644 				DRV_CALL(drv_wtm, (1));
   1645 			}
   1646 			continue;
   1647 		}
   1648 		break;
   1649 	}
   1650 	if (i == 2) {
   1651 		TRACE((MMS_ERR, "Can't write terminating FM"));
   1652 		return (EIO);
   1653 	}
   1654 
   1655 	if (dm_set_label_blksize() != 0) {
   1656 		return (EIO);
   1657 	}
   1658 
   1659 	for (i = 0; i < 2; i++) {
   1660 		if (dm_create_eof1() != 0) {
   1661 			continue;
   1662 		}
   1663 		break;
   1664 	}
   1665 	if (i == 2) {
   1666 		return (EIO);
   1667 	}
   1668 
   1669 	for (i = 0; i < 2; i++) {
   1670 		if (dm_create_eof2() != 0) {
   1671 			continue;
   1672 		}
   1673 		break;
   1674 	}
   1675 	if (i == 2) {
   1676 		return (EIO);
   1677 	}
   1678 
   1679 	for (i = 0; i < 2; i++) {
   1680 		if (DRV_CALL(drv_wtm, (2)) != 0) {
   1681 			continue;
   1682 		}
   1683 		break;
   1684 	}
   1685 	if (i == 2) {
   1686 		return (EIO);
   1687 	}
   1688 
   1689 	return (0);
   1690 }
   1691 
   1692 /*
   1693  * dm_read and dm_write are entered because we asked for it
   1694  */
   1695 int
   1696 dm_read(drm_reply_t *rep)
   1697 {
   1698 	TRACE((MMS_DEBUG, "Starting to Read"));
   1699 	if (drv->drv_flags & DRV_FATAL) {
   1700 		return (EIO);
   1701 	}
   1702 	memset(rep, 0, sizeof (rep));
   1703 
   1704 	if (drv->drv_flags & DRV_TERM_FILE) {
   1705 		/*
   1706 		 * The previous movement command was an output command.
   1707 		 * Let the driver fail this read.
   1708 		 */
   1709 		TRACE((MMS_ERR, "attempted read after write"));
   1710 		return (0);
   1711 	}
   1712 	/*
   1713 	 * Notify when switching to output
   1714 	 */
   1715 	rep->drm_rep_flags |= DRM_REP_NOTIFY_WRITE;
   1716 	return (0);
   1717 }
   1718 
   1719 int
   1720 dm_read_tm(drm_request_t *req)
   1721 {
   1722 	uint64_t	flags;
   1723 	char		buf[4096];
   1724 	tapepos_t	cur_pos = drv->drv_cur_pos;
   1725 
   1726 	/*
   1727 	 * Hit a tapemark.
   1728 	 * Check to see if we reached EOF
   1729 	 */
   1730 	if (mnt->mnt_flags & MNT_NOBSD) {
   1731 		/*
   1732 		 * Alway cross TM to check trailor labels
   1733 		 */
   1734 		DRV_CALL(drv_fsf, (1));
   1735 	}
   1736 
   1737 	if (dm_set_label_blksize()) {
   1738 		goto err;
   1739 	}
   1740 	if (drv->drv_flags & DRV_VALID_EOF_POS) {
   1741 		if (DRV_CALL(drv_get_pos, (&cur_pos)) != 0) {
   1742 			goto err;
   1743 		}
   1744 		if (cur_pos.lgclblkno > drv->drv_eof_pos.lgclblkno) {
   1745 			if (DRV_CALL(drv_locate, (&drv->drv_eof_pos)) != 0) {
   1746 				goto err;
   1747 			}
   1748 			drv->drv_cur_pos = drv->drv_eof_pos;
   1749 			drv->drv_flags &= ~DRV_TM;
   1750 			drv->drv_flags |= DRV_EOF;
   1751 		}
   1752 	} else if (dm_chk_eof() == 0) {
   1753 		if (DRV_CALL(drv_bsf, (1)) != 0) {
   1754 			goto err;
   1755 		}
   1756 		drv->drv_cur_pos = cur_pos;
   1757 		drv->drv_flags &= ~DRV_TM;
   1758 		drv->drv_flags |= DRV_EOF;
   1759 		(void) dm_get_eof_pos();
   1760 	}
   1761 
   1762 	if ((drv->drv_flags & DRV_EOF) == 0) {
   1763 		/* Not at EOF */
   1764 		if (mnt->mnt_flags & MNT_NOBSD) {
   1765 			DRV_CALL(drv_bsf, (1));
   1766 			read(drv->drv_fd, buf, sizeof (buf));
   1767 		}
   1768 		drv->drv_flags |= DRV_TM;
   1769 		drv->drv_flags &= ~DRV_EOF;
   1770 	}
   1771 
   1772 	flags = drv->drv_flags & (DRV_TM | DRV_EOF);
   1773 	dm_get_mtstat(DRV_SAVE_STAT);
   1774 	drv->drv_flags &= ~(DRV_TM | DRV_EOF);
   1775 	drv->drv_flags |= flags;
   1776 
   1777 	drv->drv_mtget.drm_resid = req->drm_err_req.drm_resid;
   1778 	if (dm_set_file_blksize(drv->drv_cur_blksize)) {
   1779 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1780 		    "Set file blksize error"));
   1781 		goto err;
   1782 	}
   1783 	return ((int)req->drm_err_req.drm_errno);
   1784 
   1785 err:
   1786 	if (dm_set_file_blksize(drv->drv_cur_blksize)) {
   1787 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1788 		    "Set file blksize error"));
   1789 	}
   1790 	drv->drv_mtget.drm_resid = req->drm_err_req.drm_resid;
   1791 	drv->drv_flags |= DRV_FATAL;
   1792 	TRACE((MMS_DEBUG, "FATAL error"));
   1793 	return (EIO);
   1794 }
   1795 
   1796 int
   1797 dm_read_err(drm_request_t *req, drm_reply_t *rep)
   1798 {
   1799 	TRACE((MMS_ERR, "Read error: resid = %lld, errno = %lld, %s",
   1800 	    req->drm_err_req.drm_resid, req->drm_err_req.drm_errno,
   1801 	    strerror(req->drm_err_req.drm_errno)));
   1802 	drv->drv_flags &= ~DRV_VALID_STAT;
   1803 	dm_get_mtstat(DRV_SAVE_STAT);
   1804 	dm_get_mt_error(EIO);
   1805 	DRV_CALL(drv_proc_error, ());
   1806 	if (serr->se_senkey == KEY_HARDWARE_ERROR) {
   1807 		/* set DriveBroken to "yes" */
   1808 		(void) dm_send_drive_broken();
   1809 	} else if (serr->se_senkey == KEY_MEDIUM_ERROR) {
   1810 		/* Set CartridgeMediaError to "yes" */
   1811 		(void) dm_send_cartridge_media_error();
   1812 	}
   1813 	rep->drm_rep_flags |= DRM_REP_NOTIFY_WRITE;
   1814 	drv->drv_mtget.drm_resid = req->drm_err_req.drm_resid;
   1815 	return ((int)req->drm_err_req.drm_errno);
   1816 
   1817 }
   1818 
   1819 int
   1820 dm_write(drm_reply_t *rep)
   1821 {
   1822 
   1823 	TRACE((MMS_DEBUG, "In dm_write"));
   1824 
   1825 	if (drv->drv_flags & DRV_FATAL) {
   1826 		return (EIO);
   1827 	}
   1828 
   1829 	/*
   1830 	 * Readonly, can't write to it
   1831 	 */
   1832 	if (drv->drv_flags & DRV_READONLY) {
   1833 		return (EACCES);
   1834 	}
   1835 
   1836 	memset(rep, 0, sizeof (rep));
   1837 	drv->drv_flags |= DRV_TERM_FILE;
   1838 	drv->drv_flags &= ~DRV_VALID_EOF_POS;
   1839 	/*
   1840 	 * DRV_UPDATE_EOF_POS is only set when valid eof flag is updated
   1841 	 */
   1842 	if ((drv->drv_flags & DRV_UPDATE_EOF_POS) == 0) {
   1843 		drv->drv_flags |= DRV_UPDATE_EOF_POS;
   1844 		(void) dm_send_eof_pos();
   1845 	}
   1846 	/*
   1847 	 * Notify when switching to input
   1848 	 */
   1849 	if (mnt->mnt_flags & MNT_MMS) {
   1850 		rep->drm_rep_flags |= DRM_REP_NOTIFY_READ;
   1851 	}
   1852 	drv->drv_flags &= ~DRV_MOVE_FLAGS;
   1853 	return (0);
   1854 }
   1855 
   1856 int
   1857 dm_write_0(drm_request_t *req, drm_reply_t *rep)
   1858 {
   1859 	TRACE((MMS_DEBUG, "In dm_write_0"));
   1860 
   1861 	memset(rep, 0, sizeof (rep));
   1862 	dm_get_mtstat(DRV_SAVE_STAT);
   1863 	/*
   1864 	 * Notify when switching to input
   1865 	 */
   1866 	rep->drm_rep_flags |= DRM_REP_NOTIFY_READ;
   1867 	drv->drv_mtget.drm_resid = req->drm_err_req.drm_resid;
   1868 	return ((int)req->drm_err_req.drm_errno);
   1869 }
   1870 
   1871 int
   1872 dm_write_err(drm_request_t *req, drm_reply_t *rep)
   1873 {
   1874 	TRACE((MMS_ERR, "Write error: resid = %lld, errno = %lld, %s",
   1875 	    req->drm_err_req.drm_resid, req->drm_err_req.drm_errno,
   1876 	    strerror(req->drm_err_req.drm_errno)));
   1877 	drv->drv_flags &= ~DRV_VALID_STAT;
   1878 	dm_get_mtstat(DRV_SAVE_STAT);
   1879 	dm_get_mt_error(EIO);
   1880 	DRV_CALL(drv_proc_error, ());
   1881 	if (serr->se_senkey == KEY_HARDWARE_ERROR) {
   1882 		/* set DriveBroken to "yes" */
   1883 		(void) dm_send_drive_broken();
   1884 	} else if (serr->se_senkey == KEY_MEDIUM_ERROR) {
   1885 		/* Set CartridgeMediaError to "yes" */
   1886 		(void) dm_send_cartridge_media_error();
   1887 	}
   1888 	rep->drm_rep_flags |= DRM_REP_NOTIFY_READ;
   1889 	drv->drv_mtget.drm_resid = req->drm_err_req.drm_resid;
   1890 	return ((int)req->drm_err_req.drm_errno);
   1891 }
   1892 
   1893 int
   1894 dm_create_vol1(void)
   1895 {
   1896 	drv_vol1_t	*vol1 = &drv->drv_vol1;
   1897 	char		dumpbuf[MMS_DUMPBUF_SIZE(80)];
   1898 	char		*vp;
   1899 	char		*buf;
   1900 
   1901 	memset(vol1, ' ', sizeof (drv_vol1_t));
   1902 	strncpy(vol1->vol1_id, "VOL1", 4);
   1903 	if (mnt->mnt_vid == NULL) {
   1904 		vp = mnt->mnt_pcl;
   1905 	} else {
   1906 		vp = mnt->mnt_vid;
   1907 	}
   1908 
   1909 	buf = mms_strapp(NULL,
   1910 	    "%-6.6s", vp);
   1911 	strncpy(vol1->vol1_vid, buf, 6);
   1912 	free(buf);
   1913 	vol1->vol1_acc = ' ';
   1914 	strncpy(vol1->vol1_impid, DRV_IMPID, 13);
   1915 	strncpy(vol1->vol1_owner, VOL1_OWNER, 14);
   1916 	vol1->vol1_ver = '4';
   1917 	(void) mms_trace_dump((char *)vol1, 80, dumpbuf, sizeof (dumpbuf));
   1918 	TRACE((MMS_DEBUG, "VOL1 label:\n%s",
   1919 	    mms_trace_dump((char *)vol1, 80, dumpbuf, sizeof (dumpbuf))));
   1920 
   1921 	if (DRV_CALL(drv_write, ((char *)vol1, 80)) != 80) {
   1922 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   1923 		    "Unable to write VOL1 label"));
   1924 		return (EIO);
   1925 	}
   1926 	drv->drv_lbl_type = DRV_AL;
   1927 	TRACE((MMS_DEBUG, "Wrote VOL1"));
   1928 	strncpy(drv->drv_vid, vol1->vol1_vid, 6);
   1929 	drv->drv_flags |= (DRV_VOL1 | DRV_IDENTIFIED);
   1930 	drv->drv_fseq = 1;
   1931 	return (0);
   1932 }
   1933 
   1934 int
   1935 dm_create_hdr1(void)
   1936 {
   1937 	drv_hdr1_t	*hdr1 = &drv->drv_hdr1;
   1938 	char		*buf;
   1939 	char		dumpbuf[MMS_DUMPBUF_SIZE(80)];
   1940 	time_t		curtime;
   1941 	struct		tm tm;
   1942 	char		*tmp;
   1943 
   1944 	memset(hdr1, ' ', sizeof (drv_hdr1_t));
   1945 
   1946 	/*
   1947 	 * Get creation date
   1948 	 */
   1949 	curtime = time(NULL);
   1950 	localtime_r(&curtime, &tm);
   1951 	if (tm.tm_year > 100) {
   1952 		tm.tm_year -= 100;
   1953 		hdr1->hdr1_cdate[0] = '0';
   1954 	} else {
   1955 		hdr1->hdr1_cdate[0] = ' ';
   1956 	}
   1957 	tmp = mms_strapp(NULL,
   1958 	    "%2.2d", tm.tm_year);
   1959 	strncpy(hdr1->hdr1_cdate + 1, tmp, 2);
   1960 	free(tmp);
   1961 	tmp = mms_strapp(NULL,
   1962 	    "%3.3d", tm.tm_yday + 1);
   1963 	free(tmp);
   1964 	strncpy(hdr1->hdr1_cdate + 3, tmp, 3);
   1965 
   1966 	/*
   1967 	 * Get expiration date
   1968 	 */
   1969 	if (drv->drv_retention == 0) {
   1970 		/* Don't use expiration date */
   1971 		strncpy(hdr1->hdr1_xdate, "000000", 6);
   1972 	} else if (drv->drv_retention == 99999) {
   1973 		/* Never expires */
   1974 		strncpy(hdr1->hdr1_xdate, "099366", 6);
   1975 	} else {
   1976 		/* expire time */
   1977 		curtime += ((drv->drv_retention + 1) * 24 * 60 * 60);
   1978 		localtime_r(&curtime, &tm);
   1979 		if (tm.tm_year > 100) {
   1980 			tm.tm_year -= 100;
   1981 			hdr1->hdr1_xdate[0] = '0';
   1982 		} else {
   1983 			hdr1->hdr1_xdate[0] = ' ';
   1984 		}
   1985 		tmp = mms_strapp(NULL,
   1986 		    "%2.2d", tm.tm_year);
   1987 		strncpy(hdr1->hdr1_xdate + 1, tmp, 2);
   1988 		free(tmp);
   1989 		tmp = mms_strapp(NULL,
   1990 		    "%3.3d", tm.tm_yday + 1);
   1991 		strncpy(hdr1->hdr1_xdate + 3, tmp, 3);
   1992 		free(tmp);
   1993 	}
   1994 
   1995 	strncpy(hdr1->hdr1_id, "HDR1", 4);
   1996 	strncpy(hdr1->hdr1_fid, mnt->mnt_fname, 17);
   1997 	strncpy(hdr1->hdr1_fsnum, "0001", 4);
   1998 	buf = mms_strapp(NULL,
   1999 	    "%4.4d", mnt->mnt_fseq);
   2000 	strncpy(hdr1->hdr1_fseq, buf, 4);
   2001 	free(buf);
   2002 	strncpy(hdr1->hdr1_gnum, "0001", 4);
   2003 	strncpy(hdr1->hdr1_gver, "00", 2);
   2004 	strncpy(hdr1->hdr1_bcount, "000000", 6);
   2005 	strncpy(hdr1->hdr1_impid, DRV_IMPID, 13);
   2006 	(void) mms_trace_dump((char *)hdr1, 80, dumpbuf, sizeof (dumpbuf));
   2007 	TRACE((MMS_DEBUG, "HDR1 label:\n%s", dumpbuf));
   2008 
   2009 
   2010 	if (DRV_CALL(drv_write, ((char *)hdr1, 80)) != 80) {
   2011 		TRACE((MMS_ERR, "Unable to write HDR1 label"));
   2012 		return (EIO);
   2013 	}
   2014 	TRACE((MMS_DEBUG, "Wrote HDR1"));
   2015 	strncpy(drv->drv_fid, mnt->mnt_fname, 17);
   2016 	drv->drv_fid[17] = '\0';
   2017 	drv->drv_flags |= (DRV_HDR1 | DRV_VALIDATED_FNAME);
   2018 	return (0);
   2019 }
   2020 
   2021 int
   2022 dm_create_hdr2(void)
   2023 {
   2024 	drv_hdr2_t	*hdr2 = &drv->drv_hdr2;
   2025 	char		*buf;
   2026 	char		dumpbuf[MMS_DUMPBUF_SIZE(80)];
   2027 
   2028 	memset(hdr2, ' ', 80);
   2029 	strncpy(hdr2->hdr2_id, "HDR2", 4);
   2030 	if (drv->drv_flags & DRV_FIXED) {
   2031 		hdr2->hdr2_rformat = 'F';
   2032 	} else {
   2033 		hdr2->hdr2_rformat = 'D';
   2034 	}
   2035 
   2036 	/*
   2037 	 * Put file blksize in label
   2038 	 */
   2039 	drv->drv_lbl_blksize = drv->drv_file_blksize;
   2040 	if (mnt->mnt_blksize < 99999) {
   2041 		buf = mms_strapp(NULL,
   2042 		    "%5.5d", drv->drv_lbl_blksize);
   2043 		strncpy(hdr2->hdr2_blklen, buf, sizeof (hdr2->hdr2_blklen));
   2044 		strncpy(hdr2->hdr2_rcdlen, buf, sizeof (hdr2->hdr2_rcdlen));
   2045 		free(buf);
   2046 	} else {
   2047 		strncpy(hdr2->hdr2_blklen, "99999", sizeof (hdr2->hdr2_blklen));
   2048 		strncpy(hdr2->hdr2_rcdlen, "99999", sizeof (hdr2->hdr2_rcdlen));
   2049 	}
   2050 	buf = mms_strapp(NULL,
   2051 	    "%10.10d", drv->drv_lbl_blksize);
   2052 	strncpy(hdr2->hdr2_blksize, buf, sizeof (hdr2->hdr2_blksize));
   2053 	free(buf);
   2054 	strncpy(hdr2->hdr2_off, "00", sizeof (hdr2->hdr2_off));
   2055 	(void) mms_trace_dump((char *)hdr2, 80, dumpbuf, sizeof (dumpbuf));
   2056 	TRACE((MMS_DEBUG, "HDR2 label:\n%s", dumpbuf));
   2057 
   2058 	if (DRV_CALL(drv_write, ((char *)hdr2, 80)) != 80) {
   2059 		TRACE((MMS_ERR, "Unable to write HDR2 label"));
   2060 		return (EIO);
   2061 	}
   2062 	TRACE((MMS_DEBUG, "Wrote HDR2"));
   2063 	drv->drv_flags |= DRV_HDR2;
   2064 	return (0);
   2065 }
   2066 
   2067 int
   2068 dm_create_eof1(void)
   2069 {
   2070 	drv_eof1_t	*eof1 = &drv->drv_eof1;
   2071 	char		*buf;
   2072 	char		dumpbuf[MMS_DUMPBUF_SIZE(80)];
   2073 
   2074 	memset(eof1, ' ', sizeof (drv_eof1_t));
   2075 	strncpy(eof1->eof1_id, "EOF1", 4);
   2076 	strncpy(eof1->eof1_fid, mnt->mnt_fname, 17);
   2077 	strncpy(eof1->eof1_fsnum, "0001", 4);
   2078 	buf = mms_strapp(NULL,
   2079 	    "%4.4d", mnt->mnt_fseq);
   2080 	strncpy(eof1->eof1_fseq, buf, sizeof (eof1->eof1_fseq));
   2081 	strncpy(eof1->eof1_gnum, "0001", sizeof (eof1->eof1_gnum));
   2082 	strncpy(eof1->eof1_gver, "00", sizeof (eof1->eof1_gver));
   2083 	strncpy(eof1->eof1_cdate, drv->drv_hdr1.hdr1_cdate,
   2084 	    sizeof (eof1->eof1_cdate));
   2085 	strncpy(eof1->eof1_xdate, drv->drv_hdr1.hdr1_xdate,
   2086 	    sizeof (eof1->eof1_xdate));
   2087 	strncpy(eof1->eof1_bcount, "000000", sizeof (eof1->eof1_bcount));
   2088 	strncpy(eof1->eof1_impid, DRV_IMPID, sizeof (eof1->eof1_impid));
   2089 	free(buf);
   2090 	(void) mms_trace_dump((char *)eof1, 80, dumpbuf, sizeof (dumpbuf));
   2091 	TRACE((MMS_DEBUG, "EOF1 label:\n%s", dumpbuf));
   2092 
   2093 	if (DRV_CALL(drv_write, ((char *)eof1, 80)) != 80) {
   2094 		TRACE((MMS_ERR, "Unable to write EOF1 label"));
   2095 		return (EIO);
   2096 	}
   2097 	TRACE((MMS_DEBUG, "Wrote EOF1"));
   2098 	strncpy(drv->drv_fid, mnt->mnt_fname, sizeof (drv->drv_fid));
   2099 	drv->drv_fid[17] = '\0';
   2100 	drv->drv_flags |= DRV_EOF1;
   2101 	return (0);
   2102 }
   2103 
   2104 int
   2105 dm_create_eof2(void)
   2106 {
   2107 	drv_eof2_t	*eof2 = &drv->drv_eof2;
   2108 	char		*buf;
   2109 	char		dumpbuf[MMS_DUMPBUF_SIZE(80)];
   2110 
   2111 	memset(eof2, ' ', 80);
   2112 	strncpy(eof2->eof2_id, "EOF2", 4);
   2113 	if (drv->drv_flags & DRV_FIXED) {
   2114 		eof2->eof2_rformat = 'F';
   2115 	} else {
   2116 		eof2->eof2_rformat = 'D';
   2117 	}
   2118 	if (mnt->mnt_blksize < 99999) {
   2119 		buf = mms_strapp(NULL,
   2120 		    "%5.5d", drv->drv_lbl_blksize);
   2121 		strncpy(eof2->eof2_blklen, buf, sizeof (eof2->eof2_blklen));
   2122 		strncpy(eof2->eof2_rcdlen, buf, sizeof (eof2->eof2_blklen));
   2123 		free(buf);
   2124 	} else {
   2125 		strncpy(eof2->eof2_blklen, "99999", sizeof (eof2->eof2_blklen));
   2126 		strncpy(eof2->eof2_rcdlen, "99999", sizeof (eof2->eof2_blklen));
   2127 	}
   2128 	buf = mms_strapp(NULL,
   2129 	    "%10.10d", drv->drv_lbl_blksize);
   2130 	strncpy(eof2->eof2_blksize, buf, sizeof (eof2->eof2_blksize));
   2131 	strncpy(eof2->eof2_off, "00", sizeof (eof2->eof2_off));
   2132 	free(buf);
   2133 	(void) mms_trace_dump((char *)eof2, 80, dumpbuf, sizeof (dumpbuf));
   2134 	TRACE((MMS_DEBUG, "EOF2 label:\n%s", dumpbuf));
   2135 
   2136 	if (DRV_CALL(drv_write, ((char *)eof2, 80)) != 80) {
   2137 		TRACE((MMS_ERR, "Unable to write EOF2 label"));
   2138 		return (EIO);
   2139 	}
   2140 	TRACE((MMS_DEBUG, "Wrote EOF2"));
   2141 	drv->drv_flags |= DRV_EOF2;
   2142 	return (0);
   2143 }
   2144 
   2145 int
   2146 dm_rewind_file(void)
   2147 {
   2148 	if ((drv->drv_flags & DRV_UDATA) == 0) {
   2149 		/*
   2150 		 * Must be in user data to rewind
   2151 		 */
   2152 		TRACE((MMS_ERR, "Not in user data. Can't rewind file"));
   2153 		return (EACCES);
   2154 	}
   2155 
   2156 	if ((drv->drv_flags & DRV_VALID_BOF_POS) == 0) {
   2157 		/*
   2158 		 * Must have valid BOF position
   2159 		 */
   2160 		TRACE((MMS_ERR,
   2161 		    "Don't have BOF position. Can't rewind file"));
   2162 		return (EACCES);
   2163 	}
   2164 
   2165 	if (drv->drv_flags & DRV_BOF) {
   2166 		/* Already at BOF */
   2167 		return (0);
   2168 	}
   2169 	if (DRV_CALL(drv_locate, (&drv->drv_bof_pos))) {
   2170 		TRACE((MMS_ERR, "Rewind file error"));
   2171 		return (EIO);
   2172 	}
   2173 	if (DRV_CALL(drv_bsb, (1, DRV_LOGICAL_CROSS_TM)) != 0) {
   2174 		if ((drv->drv_flags & DRV_TM)) {
   2175 			/* Hit a TM */
   2176 			DRV_CALL(drv_fsf, (1));
   2177 		} else if ((drv->drv_flags & DRV_BOM) == 0) {
   2178 			/* Did not hit BOM. Must be an error */
   2179 			return (EIO);
   2180 		}
   2181 	} else {
   2182 		/* Not at BOF */
   2183 		return (EIO);
   2184 	}
   2185 
   2186 	drv->drv_mtget.drm_resid = 0;
   2187 	drv->drv_flags &= ~(DRV_BOM | DRV_TM);
   2188 	drv->drv_flags |= DRV_BOF;
   2189 
   2190 	drv->drv_cur_pos = drv->drv_bof_pos;
   2191 
   2192 	return (0);
   2193 }
   2194 
   2195 int
   2196 dm_ioctl_clrerr(drm_reply_t *rep)
   2197 {
   2198 	int		rc = 0;
   2199 
   2200 	memset(rep, 0, sizeof (drm_reply_t));
   2201 	rc = DRV_CALL(drv_clrerr, ());
   2202 	return (rc);
   2203 }
   2204 
   2205 int
   2206 dm_ioctl_mtget(drm_request_t *req, drm_reply_t *rep)
   2207 {
   2208 	if ((req->drm_req_flags & DRM_REQ_MOVED) ||
   2209 	    (drv->drv_flags & DRV_VALID_STAT) == 0) {
   2210 		/* If tape moved since last signal, get new status */
   2211 		drv->drv_flags &= ~DRV_VALID_STAT;
   2212 		dm_get_mtstat(DRV_SAVE_STAT);
   2213 	}
   2214 
   2215 	memcpy(&rep->drm_mtget_rep, &drv->drv_mtget, sizeof (drm_mtget_t));
   2216 
   2217 	if (drv->drv_flags & DRV_BOF) {
   2218 		rep->drm_mtget_rep.drm_erreg = SUN_KEY_BOT;
   2219 	} else if (drv->drv_flags & DRV_EOF) {
   2220 		rep->drm_mtget_rep.drm_erreg = SUN_KEY_EOT;
   2221 	} else if (drv->drv_flags & DRV_TM) {
   2222 		rep->drm_mtget_rep.drm_erreg = SUN_KEY_EOF;
   2223 	}
   2224 
   2225 	return (0);
   2226 }
   2227 
   2228 int
   2229 dm_ioctl_rewind(void)
   2230 {
   2231 	int		rc = 0;
   2232 
   2233 	if (drv->drv_flags & DRV_FATAL) {
   2234 		return (EIO);
   2235 	}
   2236 
   2237 	drv->drv_flags &= ~(DRV_VALID_STAT | DRV_MOVE_FLAGS);
   2238 	if (drv->drv_flags & DRV_TERM_FILE) {
   2239 		if (dm_terminate_file() != 0) {
   2240 			TRACE((MMS_ERR, "Unable to terminate file"));
   2241 			rc = EIO;
   2242 		}
   2243 		drv->drv_flags &= ~DRV_TERM_FILE;
   2244 	}
   2245 
   2246 	rc = dm_rewind_file();
   2247 
   2248 	return (rc);
   2249 }
   2250 
   2251 int
   2252 dm_ioctl_fsf(int count)
   2253 {
   2254 	int		rc = 0;
   2255 	char		buf[80];
   2256 	int		bytes;
   2257 	int		i;
   2258 
   2259 	drv->drv_mtget.drm_resid = count;
   2260 	if (drv->drv_flags & DRV_FATAL) {
   2261 		return (EIO);
   2262 	}
   2263 
   2264 	drv->drv_flags &= ~(DRV_VALID_STAT | DRV_MOVE_FLAGS);
   2265 	drv->drv_flags &= ~DRV_EOF;
   2266 	if (dm_set_label_blksize()) {
   2267 		return (EIO);
   2268 	}
   2269 	for (i = 0; i < count; i++) {
   2270 		if (DRV_CALL(drv_fsf, (1)) != 0) {
   2271 			rc = EIO;
   2272 			break;
   2273 		}
   2274 		/*
   2275 		 * Try to read the next block to see if it is a trailor label.
   2276 		 */
   2277 		while ((drv->drv_flags & DRV_EOF) == 0) {
   2278 			if ((bytes = DRV_CALL(drv_read, (buf, 80))) == 80) {
   2279 				if (strncmp(buf, "EOF1", 4) == 0 ||
   2280 				    strncmp(buf, "EOV1", 4) == 0) {
   2281 					/* Read trailor label */
   2282 					/* Reposition to EOF */
   2283 					TRACE((MMS_DEBUG, "Found EOF1/EOV1"));
   2284 					DRV_CALL(drv_bsf, (1));
   2285 					drv->drv_flags &= ~DRV_TM;
   2286 					drv->drv_flags |= DRV_EOF;
   2287 					(void) dm_get_eof_pos();
   2288 					rc = EIO;
   2289 					break;
   2290 				}
   2291 			}
   2292 
   2293 			if (bytes > 0) {
   2294 				/*
   2295 				 * Read something other than a label
   2296 				 */
   2297 				if (i == (count - 1)) {
   2298 					/*
   2299 					 * Spaced requested TM
   2300 					 */
   2301 					DRV_CALL(drv_bsb,
   2302 					    (1, DRV_LOGICAL_CROSS_TM));
   2303 				}
   2304 				break;
   2305 			} else if (drv->drv_flags & DRV_TM) {
   2306 				/* Read another tapemark */
   2307 				drv->drv_flags &= ~DRV_TM;
   2308 				if (i == (count - 1)) {
   2309 					/*
   2310 					 * Spaced requested TM
   2311 					 */
   2312 					DRV_CALL(drv_bsf, (1));
   2313 					drv->drv_flags |= DRV_TM;
   2314 					break;
   2315 				} else {
   2316 					i++;		/* skipped another TM */
   2317 				}
   2318 				continue;	/* try to read label again */
   2319 			} else if (rc < 0) {
   2320 				if (serr->se_senkey == SUN_KEY_EOT ||
   2321 				    serr->se_senkey == KEY_BLANK_CHECK) {
   2322 					/* Hit EOM or blank check */
   2323 					TRACE((MMS_DEBUG,
   2324 					    "Hit EOT/BLANK CHECK"));
   2325 					drv->drv_flags |= DRV_EOF;
   2326 					if (dm_get_eof_pos()) {
   2327 						rc = EIO;
   2328 						goto done;
   2329 					}
   2330 					break;
   2331 				} else {
   2332 					/* Other error */
   2333 					rc = EIO;
   2334 					goto done;
   2335 				}
   2336 			} else {
   2337 				/*
   2338 				 * Some unknown error
   2339 				 */
   2340 				rc = EIO;
   2341 				break;
   2342 			}
   2343 		}
   2344 
   2345 		/*
   2346 		 * Done if we are at EOF
   2347 		 */
   2348 		if (drv->drv_flags & DRV_EOF) {
   2349 			break;
   2350 		}
   2351 	}
   2352 
   2353 
   2354 done:
   2355 	dm_get_mtstat(DRV_SAVE_STAT);
   2356 	if (dm_set_file_blksize(drv->drv_cur_blksize)) {
   2357 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   2358 		    "Set file blksize error"));
   2359 		rc = EIO;
   2360 	}
   2361 	drv->drv_mtget.drm_resid = count - i;
   2362 
   2363 	return (rc);
   2364 }
   2365 
   2366 int
   2367 dm_ioctl_fsb(int count)
   2368 {
   2369 	uint64_t	flags;
   2370 	uint64_t	resid = 0;
   2371 	int		rc = 0;
   2372 	tapepos_t	pos;
   2373 
   2374 	if (drv->drv_flags & DRV_FATAL) {
   2375 		return (EIO);
   2376 	}
   2377 
   2378 	drv->drv_flags &= ~DRV_VALID_STAT;
   2379 	drv->drv_flags &= ~DRV_MOVE_FLAGS;
   2380 
   2381 	if (dm_set_label_blksize()) {
   2382 		return (EIO);
   2383 	}
   2384 	if (DRV_CALL(drv_fsb, (count, DRV_LOGICAL_CROSS_TM)) != 0) {
   2385 		resid = serr->se_resid;
   2386 		if (drv->drv_flags & DRV_TM) {
   2387 			/*
   2388 			 * Hit a tapemark.
   2389 			 * Check to see if we reached EOF
   2390 			 */
   2391 			DRV_CALL(drv_get_pos, (&pos));
   2392 			if (drv->drv_flags & DRV_VALID_EOF_POS) {
   2393 				if (pos.lgclblkno >=
   2394 				    drv->drv_eof_pos.lgclblkno) {
   2395 					/* passed EOF position */
   2396 					DRV_CALL(drv_bsf, (1));
   2397 					drv->drv_flags &= ~DRV_TM;
   2398 					drv->drv_flags |= DRV_EOF;
   2399 					drv->drv_cur_pos = drv->drv_eof_pos;
   2400 				}
   2401 			} else if (dm_chk_eof() == 0) {
   2402 				/* Not at EOF, check if at EOF */
   2403 				DRV_CALL(drv_bsf, (1));
   2404 				drv->drv_flags &= ~DRV_TM;
   2405 				drv->drv_flags |= DRV_EOF;
   2406 			}
   2407 			/*
   2408 			 * If at EOF, and don't have EOF position, get it
   2409 			 */
   2410 			if (drv->drv_flags & DRV_EOF) {
   2411 				if ((drv->drv_flags & DRV_VALID_EOF_POS) == 0) {
   2412 					(void) dm_get_eof_pos();
   2413 					drv->drv_cur_pos = drv->drv_eof_pos;
   2414 				}
   2415 			} else {
   2416 				/*
   2417 				 * If not at EOF, must have hit a TM
   2418 				 */
   2419 				drv->drv_flags |= DRV_TM;
   2420 				/*
   2421 				 * Deal with Solaris BSB/NOBSD behavior
   2422 				 */
   2423 				if ((mnt->mnt_flags & MNT_MMS_TM) == 0) {
   2424 					/* Not MMS TM, then do not cross TM */
   2425 					DRV_CALL(drv_bsf, (1));
   2426 					DRV_CALL(drv_fsb,
   2427 					    (1, ~DRV_LOGICAL_CROSS_TM));
   2428 				}
   2429 			}
   2430 		}
   2431 		rc = EIO;
   2432 	}
   2433 
   2434 	if (dm_set_file_blksize(drv->drv_cur_blksize)) {
   2435 		DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL,
   2436 		    "Set file blksize error"));
   2437 		rc = EIO;
   2438 	}
   2439 	flags = drv->drv_flags & (DRV_EOF | DRV_TM);
   2440 	dm_get_mtstat(DRV_SAVE_STAT);
   2441 	drv->drv_flags &= ~(DRV_EOF | DRV_TM);
   2442 	drv->drv_flags |= flags;
   2443 	drv->drv_mtget.drm_resid = resid;
   2444 
   2445 	return (rc);
   2446 }
   2447 
   2448 int
   2449 dm_ioctl_bsf(int count)
   2450 {
   2451 	int		rc = 0;
   2452 	int		i;
   2453 	tapepos_t	pos;
   2454 
   2455 	if (drv->drv_flags & DRV_FATAL) {
   2456 		return (EIO);
   2457 	}
   2458 	if (drv->drv_flags & DRV_TERM_FILE) {
   2459 		if (dm_terminate_file() != 0) {
   2460 			TRACE((MMS_ERR, "Write trailor label error"));
   2461 			rc = EIO;
   2462 		}
   2463 		drv->drv_flags &= ~DRV_TERM_FILE;
   2464 	}
   2465 
   2466 	drv->drv_flags &= ~DRV_VALID_STAT;
   2467 	drv->drv_flags &= ~DRV_MOVE_FLAGS;
   2468 	for (i = 0; i < count; i++) {
   2469 		DRV_CALL(drv_bsf, (1));
   2470 		DRV_CALL(drv_get_pos, (&pos));
   2471 		if (pos.lgclblkno < drv->drv_bof_pos.lgclblkno) {
   2472 			DRV_CALL(drv_locate, (&drv->drv_bof_pos));
   2473 			drv->drv_flags |= DRV_BOF;
   2474 			drv->drv_cur_pos = drv->drv_bof_pos;
   2475 			rc = EIO;
   2476 			break;
   2477 		}
   2478 	}
   2479 
   2480 	dm_get_mtstat(DRV_SAVE_STAT);
   2481 	drv->drv_mtget.drm_resid = count - i;
   2482 	if (serr->se_resid == 0) {
   2483 		drv->drv_flags |= DRV_TM;
   2484 	}
   2485 
   2486 	return (rc);
   2487 }
   2488 
   2489 int
   2490 dm_ioctl_bsb(int count)
   2491 {
   2492 	tapepos_t	pos;
   2493 	int		cross;
   2494 	int		resid = 0;
   2495 	int		flags;
   2496 	int		rc = 0;
   2497 	int		err = 0;
   2498 
   2499 	if (drv->drv_flags & DRV_FATAL) {
   2500 		return (EIO);
   2501 	}
   2502 
   2503 	if (drv->drv_flags & DRV_TERM_FILE) {
   2504 		if (dm_terminate_file() != 0) {
   2505 			TRACE((MMS_ERR, "Write trailor label error"));
   2506 			return (EIO);
   2507 		}
   2508 		drv->drv_flags &= ~DRV_TERM_FILE;
   2509 	}
   2510 
   2511 	drv->drv_flags &= ~DRV_VALID_STAT;
   2512 	drv->drv_flags &= ~DRV_MOVE_FLAGS;
   2513 	if (mnt->mnt_flags & MNT_MMS_TM) {
   2514 		cross = DRV_LOGICAL_CROSS_TM;
   2515 	} else {
   2516 		cross = ~DRV_LOGICAL_CROSS_TM;
   2517 	}
   2518 	if (DRV_CALL(drv_bsb, (count, cross)) != 0) {
   2519 		err = errno;
   2520 		resid = serr->se_resid;
   2521 		if (drv->drv_flags & DRV_TM) {
   2522 			/* Hit a tapemark */
   2523 			DRV_CALL(drv_get_pos, (&pos));
   2524 			if (pos.lgclblkno <= drv->drv_bof_pos.lgclblkno) {
   2525 				if (DRV_CALL(drv_locate, (&drv->drv_bof_pos))) {
   2526 					/* Failed to reposition */
   2527 					rc = EIO;
   2528 				} else {
   2529 					drv->drv_flags &= ~DRV_TM;
   2530 					drv->drv_flags |= DRV_BOF;
   2531 					drv->drv_cur_pos = drv->drv_bof_pos;
   2532 				}
   2533 			}
   2534 		}
   2535 		rc = EIO;
   2536 		errno = err;
   2537 	}
   2538 
   2539 	flags = drv->drv_flags & (DRV_TM | DRV_BOF);
   2540 	dm_get_mtstat(DRV_SAVE_STAT);
   2541 	drv->drv_flags &= ~(DRV_TM | DRV_BOF);
   2542 	drv->drv_flags |= flags;
   2543 	drv->drv_mtget.drm_resid = resid;
   2544 
   2545 	return (rc);
   2546 }
   2547 
   2548 int
   2549 dm_ioctl_seek(int count)
   2550 {
   2551 	int		rc = 0;
   2552 	uint64_t	flags;
   2553 
   2554 	if (drv->drv_flags & DRV_FATAL) {
   2555 		return (EIO);
   2556 	}
   2557 
   2558 	if (drv->drv_flags & DRV_TERM_FILE) {
   2559 		if (dm_terminate_file() != 0) {
   2560 			TRACE((MMS_ERR, "Write trailor label error"));
   2561 			return (EIO);
   2562 		}
   2563 		drv->drv_flags &= ~DRV_TERM_FILE;
   2564 	}
   2565 
   2566 	drv->drv_flags &= ~DRV_VALID_STAT;
   2567 	drv->drv_flags &= ~DRV_MOVE_FLAGS;
   2568 
   2569 	rc = DRV_CALL(drv_seek, ((uint64_t)count));
   2570 	if (rc) {
   2571 		DM_MSG_SEND((DM_ADM_ERR, DM_6522_MSG, DM_MSG_REASON));
   2572 		rc = EIO;
   2573 	}
   2574 
   2575 	flags = drv->drv_flags & (DRV_TM | DRV_BOF);
   2576 	dm_get_mtstat(DRV_SAVE_STAT);
   2577 	drv->drv_flags &= ~(DRV_TM | DRV_BOF);
   2578 	drv->drv_flags |= flags;
   2579 
   2580 	return (rc);
   2581 }
   2582 
   2583 int
   2584 dm_ioctl_wtm(int count)
   2585 {
   2586 	int		rc = 0;
   2587 	int		resid = 0;
   2588 
   2589 	if (drv->drv_flags & DRV_FATAL) {
   2590 		return (EIO);
   2591 	}
   2592 
   2593 	/*
   2594 	 * Readonly, can't write to it
   2595 	 */
   2596 	if (drv->drv_flags & DRV_READONLY) {
   2597 		if (count > 0) {
   2598 			return (EACCES);
   2599 		}
   2600 	}
   2601 
   2602 	drv->drv_flags &= ~DRV_MOVE_FLAGS;
   2603 	drv->drv_flags &= ~DRV_VALID_EOF_POS;
   2604 	drv->drv_flags &= ~DRV_VALID_STAT;
   2605 	if (count > 0) {
   2606 		/* Terminate file if writing TM to tape */
   2607 		drv->drv_flags |= DRV_TERM_FILE;
   2608 	}
   2609 
   2610 	if (DRV_CALL(drv_wtm, (count)) != 0) {
   2611 		resid = serr->se_resid;
   2612 		rc = EIO;
   2613 	}
   2614 	dm_get_mtstat(DRV_SAVE_STAT);
   2615 	if (resid != count) {
   2616 		/* Wrote some TM */
   2617 		drv->drv_flags |= DRV_TM;
   2618 	}
   2619 	drv->drv_mtget.drm_resid = resid;
   2620 
   2621 	return (rc);
   2622 }
   2623 
   2624 int
   2625 dm_ioctl_set_blksize(uint64_t blksize)
   2626 {
   2627 	int	rc;
   2628 
   2629 	rc = DRV_CALL(drv_set_blksize, (blksize));
   2630 
   2631 	if (rc) {
   2632 		DM_MSG_SEND((DM_ADM_ERR, DM_6513_MSG, DM_MSG_REASON));
   2633 		return (rc);
   2634 	}
   2635 	if ((drv->drv_cur_blksize = blksize) == 0) {
   2636 		drv->drv_flags &= ~DRV_FIXED;
   2637 	} else {
   2638 		drv->drv_flags |= DRV_FIXED;
   2639 	}
   2640 	return (0);
   2641 }
   2642 
   2643 int
   2644 dm_ioctl_getpos(drm_reply_t *rep)
   2645 {
   2646 	tapepos_t	pos;
   2647 
   2648 	if (drv->drv_flags & DRV_FATAL) {
   2649 		return (EIO);
   2650 	}
   2651 
   2652 	if (DRV_CALL(drv_get_pos, (&pos)) != 0) {
   2653 		return (EIO);
   2654 	}
   2655 	rep->drm_pos_rep.mms_pos = pos.lgclblkno;
   2656 
   2657 	return (0);
   2658 }
   2659 
   2660 int
   2661 dm_ioctl_mtgetpos(drm_reply_t *rep)
   2662 {
   2663 	if (drv->drv_flags & DRV_FATAL) {
   2664 		return (EIO);
   2665 	}
   2666 
   2667 	if (DRV_CALL(drv_get_pos, (&rep->drm_mtpos_rep)) != 0) {
   2668 		return (EIO);
   2669 	}
   2670 
   2671 	return (0);
   2672 }
   2673 
   2674 int
   2675 dm_ioctl_mtrestpos(drm_request_t *req)
   2676 {
   2677 	if (drv->drv_flags & DRV_FATAL) {
   2678 		return (EIO);
   2679 	}
   2680 
   2681 	if (DRV_CALL(drv_locate, (&req->drm_mtpos_req)) != 0) {
   2682 		return (EIO);
   2683 	}
   2684 
   2685 	return (0);
   2686 }
   2687 
   2688 int
   2689 dm_ioctl_locate(drm_request_t *req)
   2690 {
   2691 	int		rc = 0;
   2692 	uint64_t	blkno = req->drm_pos_req.mms_pos;
   2693 	tapepos_t	pos;
   2694 
   2695 	if (drv->drv_flags & DRV_FATAL) {
   2696 		return (EIO);
   2697 	}
   2698 
   2699 	if ((drv->drv_flags & DRV_VALID_EOF_POS) &&
   2700 	    drv->drv_eof_pos.lgclblkno < blkno) {
   2701 		TRACE((MMS_ERR, "Invalid locate to position: %lld",
   2702 		    blkno));
   2703 		return (EINVAL);
   2704 	}
   2705 	if (drv->drv_flags & DRV_TERM_FILE) {
   2706 		if (dm_terminate_file() != 0) {
   2707 			TRACE((MMS_ERR, "Unable to terminate file"));
   2708 			rc = EIO;
   2709 		}
   2710 		drv->drv_flags &= ~DRV_TERM_FILE;
   2711 	}
   2712 
   2713 	memset(&pos, 0, sizeof (tapepos_t));
   2714 	pos.lgclblkno = blkno;
   2715 	pos.eof = ST_NO_EOF;
   2716 	pos.pmode = logical;
   2717 	if (DRV_CALL(drv_locate, (&pos)) != 0) {
   2718 		rc = EIO;
   2719 	}
   2720 	return (rc);
   2721 }
   2722 
   2723 int
   2724 dm_ioctl_get_capacity(drm_reply_t *rep)
   2725 {
   2726 	int		rc = 0;
   2727 	mms_capacity_t	*cap = &rep->drm_cap_rep;
   2728 
   2729 	if (DRV_CALL(drv_get_capacity, (cap)) != 0) {
   2730 		rc = EIO;
   2731 	}
   2732 	return (rc);
   2733 }
   2734 
   2735 int
   2736 dm_ioctl_upt_capacity(void)
   2737 {
   2738 	int		rc = 0;
   2739 
   2740 	if (dm_update_capacity() != 0) {
   2741 		rc = EIO;
   2742 	}
   2743 	return (rc);
   2744 }
   2745 
   2746 int
   2747 dm_ioctl_set_density(void)
   2748 {
   2749 	int		rc = 0;
   2750 
   2751 	if (drv->drv_flags & DRV_FATAL) {
   2752 		return (EIO);
   2753 	}
   2754 
   2755 	if ((mnt->mnt_flags & MNT_AUTO_DEN) == 0) {
   2756 		if (DRV_CALL(drv_set_density,
   2757 		    (mnt->mnt_density->sym_code)) != 0) {
   2758 			drv->drv_flags |= DRV_FATAL;
   2759 			TRACE((MMS_DEBUG, "FATAL error"));
   2760 			rc = EIO;
   2761 		}
   2762 	}
   2763 	return (rc);
   2764 }
   2765 
   2766 int
   2767 dm_ioctl_get_density(drm_reply_t *rep)
   2768 {
   2769 	int		rc = 0;
   2770 	int		den;
   2771 
   2772 	if (DRV_CALL(drv_get_density, (&den, NULL)) != 0) {
   2773 		rc = EIO;
   2774 	} else {
   2775 		rep->drm_den_rep = den;
   2776 	}
   2777 	return (rc);
   2778 }
   2779 
   2780 void
   2781 dm_clear_dev(void)
   2782 {
   2783 	int		i;
   2784 
   2785 	/*
   2786 	 * Get rid of all attentions
   2787 	 */
   2788 	for (i = 0; i < 10; i++) {
   2789 		DRV_CALL(drv_tur, ());
   2790 	}
   2791 }
   2792 
   2793 int
   2794 dm_set_label_blksize(void)
   2795 {
   2796 	if (DRV_CALL(drv_set_blksize, (0)) != 0) {
   2797 		return (EIO);
   2798 	}
   2799 	if (DRV_CALL(drv_set_compression, (0)) != 0) {
   2800 		return (EIO);
   2801 	}
   2802 	return (0);
   2803 }
   2804 
   2805 int
   2806 dm_set_file_blksize(int blksize)
   2807 {
   2808 	int		rc;
   2809 	int		comp;
   2810 	int		bz;
   2811 	drm_blksize_t	blk;
   2812 
   2813 	if (drv->drv_flags & DRV_FATAL) {
   2814 		return (EIO);
   2815 	}
   2816 
   2817 	/*
   2818 	 * If blksize == -1, determine the blocksize.
   2819 	 * If blksize >= 0, use blksize
   2820 	 */
   2821 	if (blksize == -1) {
   2822 		if (drv->drv_file_blksize <= 0) {
   2823 			drv->drv_file_blksize = drv->drv_dflt_blksize;
   2824 		}
   2825 
   2826 		if (drv->drv_flags & DRV_FIXED) {
   2827 			bz = drv->drv_file_blksize;
   2828 		} else {
   2829 			bz = 0;
   2830 		}
   2831 	} else {
   2832 		bz = blksize;
   2833 	}
   2834 
   2835 	/*
   2836 	 * Set tape compression
   2837 	 */
   2838 	comp = (mnt->mnt_flags & MNT_COMPRESSION) ? 1 : 0;
   2839 
   2840 	if (DRV_CALL(drv_set_blksize, (bz)) != 0) {
   2841 		TRACE((MMS_ERR, "Unable to set tape blksize"));
   2842 		return (EIO);
   2843 	} else if (DRV_CALL(drv_set_compression, (comp)) != 0) {
   2844 		TRACE((MMS_ERR, "Unable to set tape compression: %d",
   2845 		    comp));
   2846 		return (EIO);
   2847 	} else {
   2848 		drv->drv_cur_blksize = bz;
   2849 		blk.drm_fixed = (drv->drv_flags & DRV_FIXED) ? 1 : 0;
   2850 		blk.drm_blksize = drv->drv_file_blksize;
   2851 		rc = ioctl(drv->drv_fd, DRM_BLKSIZE, &blk);
   2852 		TRACE((MMS_DEBUG, "Max blksize %lld", blk.drm_blksize));
   2853 	}
   2854 
   2855 	return (rc == 0 ? 0 : EIO);
   2856 }
   2857