2 * Copyright (c) 1998,1999,2000
3 * Traakan, Inc., Los Altos, CA
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include "ndmagents.h"
41 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
44 int simu_back_one (struct ndm_session *sess, int over_file_mark);
45 int simu_forw_one (struct ndm_session *sess, int over_file_mark);
46 int simu_flush_weof (struct ndm_session *sess);
49 #ifdef NDMOS_OPTION_TAPE_SIMULATOR
51 #define SIMU_GAP_MAGIC 0x0BEEFEE0
52 #define SIMU_GAP_RT_(a,b,c,d) ((a<<0)+(b<<8)+(c<<16)+(d<<24))
53 #define SIMU_GAP_RT_BOT SIMU_GAP_RT_('B','O','T','_')
54 #define SIMU_GAP_RT_DATA SIMU_GAP_RT_('D','A','T','A')
55 #define SIMU_GAP_RT_FILE SIMU_GAP_RT_('F','I','L','E')
56 #define SIMU_GAP_RT_EOT SIMU_GAP_RT_('E','O','T','_')
61 ndmos_tape_initialize (struct ndm_session *sess)
63 struct ndm_tape_agent * ta = &sess->tape_acb;
66 NDMOS_MACRO_ZEROFILL (&ta->tape_state);
67 ta->tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
68 ta->tape_state.state = NDMP9_TAPE_STATE_IDLE;
74 ndmos_tape_open (struct ndm_session *sess, char *drive_name, int will_write)
76 struct ndm_tape_agent * ta = &sess->tape_acb;
81 if (ta->tape_fd >= 0) {
82 return NDMP9_DEVICE_OPENED_ERR;
85 if (*drive_name >= '0' && *drive_name <= '9') {
86 fd = atoi(drive_name);
87 goto skip_header_check;
90 if (stat (drive_name, &st) < 0) {
91 return NDMP9_NO_DEVICE_ERR;
94 read_only = (st.st_mode & 0222) == 0;
100 return NDMP9_WRITE_PROTECT_ERR;
101 omode = 2; /* ndmp_write means read/write */
104 fd = open (drive_name, omode);
106 return NDMP9_PERMISSION_ERR;
109 if (st.st_size == 0) {
111 lseek (fd, (off_t)0, 0);
113 goto skip_header_check;
119 NDMOS_API_BZERO (ta->drive_name, sizeof ta->drive_name);
120 strcpy (ta->drive_name, drive_name);
121 bzero (&ta->tape_state, sizeof ta->tape_state);
122 ta->tape_state.error = NDMP9_NO_ERR;
123 ta->tape_state.state = NDMP9_TAPE_STATE_OPEN;
124 ta->tape_state.open_mode =
125 will_write ? NDMP9_TAPE_RDWR_MODE : NDMP9_TAPE_READ_MODE;
126 ta->tape_state.file_num.valid = NDMP9_VALIDITY_VALID;
127 ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_VALID;
128 ta->tape_state.block_size.valid = NDMP9_VALIDITY_VALID;
129 ta->tape_state.blockno.valid = NDMP9_VALIDITY_VALID;
130 ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID;
131 ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID;
137 ndmos_tape_close (struct ndm_session *sess)
139 struct ndm_tape_agent * ta = &sess->tape_acb;
141 if (ta->tape_fd < 0) {
142 return NDMP9_DEV_NOT_OPEN_ERR;
145 simu_flush_weof(sess);
149 ndmos_tape_mtio (sess, NDMP9_MTIO_REW, 1, &resid);
155 ndmos_tape_initialize (sess);
161 ndmos_tape_sync_state (struct ndm_session *sess)
163 struct ndm_tape_agent * ta = &sess->tape_acb;
165 if (ta->tape_fd < 0) {
166 ta->tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
167 ta->tape_state.state = NDMP9_TAPE_STATE_IDLE;
168 ta->tape_state.file_num.valid = NDMP9_VALIDITY_INVALID;
169 ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_INVALID;
170 ta->tape_state.block_size.valid = NDMP9_VALIDITY_INVALID;
171 ta->tape_state.blockno.valid = NDMP9_VALIDITY_INVALID;
172 ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID;
173 ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID;
175 ta->tape_state.error = NDMP9_NO_ERR;
176 if (ta->mover_state.state == NDMP9_MOVER_STATE_ACTIVE)
177 ta->tape_state.state = NDMP9_TAPE_STATE_MOVER;
179 ta->tape_state.state = NDMP9_TAPE_STATE_OPEN;
180 ta->tape_state.file_num.valid = NDMP9_VALIDITY_VALID;
181 ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_VALID;
182 ta->tape_state.block_size.valid = NDMP9_VALIDITY_VALID;
183 ta->tape_state.blockno.valid = NDMP9_VALIDITY_VALID;
184 ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID;
185 ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID;
192 simu_back_one (struct ndm_session *sess, int over_file_mark)
194 struct ndm_tape_agent * ta = &sess->tape_acb;
197 cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
198 lseek (ta->tape_fd, 0, 0);
203 simu_forw_one (struct ndm_session *sess, int over_file_mark)
205 struct ndm_tape_agent * ta = &sess->tape_acb;
208 cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
214 simu_flush_weof (struct ndm_session *sess)
216 struct ndm_tape_agent * ta = &sess->tape_acb;
218 if (ta->weof_on_close) {
220 ndmos_tape_wfm (sess);
227 ndmos_tape_mtio (struct ndm_session *sess,
228 ndmp9_tape_mtio_op op, u_long count, u_long *resid)
230 struct ndm_tape_agent * ta = &sess->tape_acb;
235 if (ta->tape_fd < 0) {
236 return NDMP9_DEV_NOT_OPEN_ERR;
240 /* audit for valid op and for tape mode */
245 simu_flush_weof(sess);
246 rc = simu_forw_one (sess, 1);
251 if (rc == SIMU_GAP_RT_FILE)
259 simu_flush_weof(sess);
260 rc = simu_back_one (sess, 1);
265 if (rc == SIMU_GAP_RT_FILE)
273 simu_flush_weof(sess);
274 rc = simu_forw_one (sess, 0);
286 simu_flush_weof(sess);
287 rc = simu_back_one (sess, 0);
297 simu_flush_weof(sess);
299 ta->tape_state.file_num.value = 0;
300 ta->tape_state.blockno.value = 0;
301 //lseek (ta->tape_fd, (off_t)(sizeof (struct simu_gap)), 0);
302 lseek (ta->tape_fd, (off_t)0, 0);
303 ndmalogf(sess, 0, 7, "NDMP9_MTIO_REW");
309 simu_flush_weof(sess);
313 case NDMP9_MTIO_EOF: /* should be "WFM" write-file-mark */
315 if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
316 return NDMP9_PERMISSION_ERR;
321 err = ndmos_tape_wfm (sess);
322 if (err != NDMP9_NO_ERR)
330 return NDMP9_ILLEGAL_ARGS_ERR;
337 ndmos_tape_write (struct ndm_session *sess,
338 char *buf, u_long count, u_long *done_count)
340 struct ndm_tape_agent * ta = &sess->tape_acb;
346 if (ta->tape_fd < 0) {
347 return NDMP9_DEV_NOT_OPEN_ERR;
350 if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
351 return NDMP9_PERMISSION_ERR;
356 * NDMPv4 clarification -- a tape read or write with
357 * a count==0 is a no-op. This is undoubtedly influenced
358 * by the SCSI Sequential Access specification which
359 * says much the same thing.
365 cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
366 lseek (ta->tape_fd, cur_pos, 0);
368 if ((u_long)full_write (ta->tape_fd, buf, count) == count) {
373 ta->tape_state.blockno.value++;
379 ndmalogf(sess, 0, 7, "full_write not %d", count);
383 /* error ignored for pipe file descriptor */
384 rc = ftruncate (ta->tape_fd, cur_pos);
386 lseek (ta->tape_fd, cur_pos, 0);
388 ta->weof_on_close = 1;
394 ndmos_tape_wfm (struct ndm_session *sess)
396 struct ndm_tape_agent * ta = &sess->tape_acb;
401 ta->weof_on_close = 0;
403 if (ta->tape_fd < 0) {
404 return NDMP9_DEV_NOT_OPEN_ERR;
407 if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
408 return NDMP9_PERMISSION_ERR;
411 cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
413 lseek (ta->tape_fd, cur_pos, 0);
416 /* error ignored for pipe file descriptor */
417 rc = ftruncate (ta->tape_fd, cur_pos);
419 lseek (ta->tape_fd, cur_pos, 0);
425 ndmos_tape_read (struct ndm_session *sess,
426 char *buf, u_long count, u_long *done_count)
428 struct ndm_tape_agent * ta = &sess->tape_acb;
432 if (ta->tape_fd < 0) {
433 return NDMP9_DEV_NOT_OPEN_ERR;
438 * NDMPv4 clarification -- a tape read or write with
439 * a count==0 is a no-op. This is undoubtedly influenced
440 * by the SCSI Sequential Access specification which
441 * says much the same thing.
450 rc = full_read (ta->tape_fd, buf, nb);
454 ta->tape_state.blockno.value++;
459 return NDMP9_EOF_ERR;
464 #endif /* NDMOS_OPTION_TAPE_SIMULATOR */
466 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */