1 /* $Id: scsi-tape.c,v 1.8 2007/09/06 23:19:06 fredette Exp $ */
2
3 /* scsi/scsi-tape.c - implementation of SCSI tape emulation: */
4
5 /*
6 * Copyright (c) 2003 Matt Fredette
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Matt Fredette.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <tme/common.h>
37 _TME_RCSID("$Id: scsi-tape.c,v 1.8 2007/09/06 23:19:06 fredette Exp $");
38
39 /* includes: */
40 #include <tme/scsi/scsi-tape.h>
41 #ifdef HAVE_STDARG_H
42 #include <stdarg.h>
43 #else /* HAVE_STDARG_H */
44 #include <varargs.h>
45 #endif /* HAVE_STDARG_H */
46
47 /* macros: */
48
49 /* globals: */
50
51 /* the list of tapes that we emulate: */
52 const struct {
53
54 /* the type name: */
55 const char *_tme_scsi_tape_list_type;
56
57 /* the initialization function: */
58 int (*_tme_scsi_tape_list_init) _TME_P((struct tme_scsi_tape *));
59 } _tme_scsi_tape_list[] = {
60
61 /* the generic TME SCSI-1 tape: */
62 { "tme-scsi-1", tme_scsi_tape_tme_init },
63
64 /* the Emulex MT02 emulation: */
65 { "emulex-mt02", tme_scsi_tape_emulexmt02_init },
66 };
67
68 /* this is the LUN addresser for LUN-aware tape devices: */
69 int
tme_scsi_tape_address_lun_aware(struct tme_scsi_device * scsi_device)70 tme_scsi_tape_address_lun_aware(struct tme_scsi_device *scsi_device)
71 {
72 struct tme_scsi_tape *scsi_tape;
73 struct tme_scsi_tape_connection *conn_scsi_tape;
74 struct tme_scsi_device_sense *sense;
75 int lun;
76
77 /* recover our data structure: */
78 scsi_tape = (struct tme_scsi_tape *) scsi_device;
79
80 /* if an IDENTIFY message was sent, use that LUN: */
81 lun = scsi_device->tme_scsi_device_addressed_lun;
82
83 /* otherwise, get the LUN from bits 5-7 of the second
84 CDB byte: */
85 if (lun < 0) {
86 lun = (scsi_device->tme_scsi_device_cdb[1] >> 5);
87 scsi_device->tme_scsi_device_addressed_lun = lun;
88 }
89
90 /* get this LUN's tape connection: */
91 conn_scsi_tape = scsi_tape->tme_scsi_tape_connections[lun];
92
93 /* if this LUN is not defined, and this isn't a REQUEST SENSE
94 command: */
95 if (!(scsi_device->tme_scsi_device_luns
96 & TME_BIT(lun))
97 && (scsi_device->tme_scsi_device_cdb[0]
98 != TME_SCSI_CDB_REQUEST_SENSE)) {
99
100 /* form the ILLEGAL REQUEST sense: */
101 sense = &scsi_device->tme_scsi_device_sense[lun];
102 sense->tme_scsi_device_sense_data[2] = 0x05;
103 }
104
105 /* otherwise, this LUN is defined. an INQUIRY or REQUEST SENSE
106 command is always allowed for a defined LUN: */
107 else if ((scsi_device->tme_scsi_device_cdb[0]
108 == TME_SCSI_CDB_INQUIRY)
109 || (scsi_device->tme_scsi_device_cdb[0]
110 == TME_SCSI_CDB_REQUEST_SENSE)) {
111 sense = NULL;
112 }
113
114 /* otherwise, if the tape at this LUN has an attention condition: */
115 else if (conn_scsi_tape->tme_scsi_tape_connection_flags
116 & TME_SCSI_TAPE_FLAG_ATTENTION) {
117
118 /* clear the attention condition: */
119 conn_scsi_tape->tme_scsi_tape_connection_flags
120 &= ~TME_SCSI_TAPE_FLAG_ATTENTION;
121
122 /* form the UNIT ATTENTION sense: */
123 sense = &scsi_device->tme_scsi_device_sense[lun];
124 sense->tme_scsi_device_sense_data[2] = 0x06;
125 }
126
127 /* otherwise, if the tape at this LUN is not loaded: */
128 else if (!(conn_scsi_tape->tme_scsi_tape_connection_flags
129 & TME_SCSI_TAPE_FLAG_LOADED)) {
130
131 /* form the NOT READY sense: */
132 sense = &scsi_device->tme_scsi_device_sense[lun];
133 sense->tme_scsi_device_sense_data[2] = 0x02;
134 }
135
136 /* otherwise, this command is okay: */
137 else {
138 sense = NULL;
139 }
140
141 /* if addressing this LUN caused some sense: */
142 if (sense != NULL) {
143
144 /* this target must support extended sense: */
145 assert (!scsi_device->tme_scsi_device_sense_no_extended);
146
147 /* the error class and error code: */
148 sense->tme_scsi_device_sense_data[0]
149 = 0x70;
150
151 /* the additional sense length: */
152 sense->tme_scsi_device_sense_data[7]
153 = 0x00;
154
155 sense->tme_scsi_device_sense_valid
156 = TRUE;
157
158 /* return the CHECK CONDITION status: */
159 tme_scsi_device_target_do_smf(scsi_device,
160 TME_SCSI_STATUS_CHECK_CONDITION,
161 TME_SCSI_MSG_CMD_COMPLETE);
162 return (EINVAL);
163 }
164
165 return (TME_OK);
166 }
167
168 /* this is the LUN addresser for LUN-unaware devices: */
169 int
tme_scsi_tape_address_lun_unaware(struct tme_scsi_device * scsi_device)170 tme_scsi_tape_address_lun_unaware(struct tme_scsi_device *scsi_device)
171 {
172
173 /* we always force a LUN of zero: */
174 scsi_device->tme_scsi_device_addressed_lun = 0;
175
176 return (tme_scsi_tape_address_lun_aware(scsi_device));
177 }
178
179 /* this determines the status of a tape READ or WRITE command: */
180 tme_uint8_t
tme_scsi_tape_xfer_status(struct tme_scsi_tape * scsi_tape,int flags,unsigned long count_xfer_got)181 tme_scsi_tape_xfer_status(struct tme_scsi_tape *scsi_tape,
182 int flags,
183 unsigned long count_xfer_got)
184 {
185 int lun;
186 tme_uint8_t *cdb;
187 tme_uint8_t status;
188 unsigned long count_xfer_wanted;
189 struct tme_scsi_device_sense *sense;
190
191 /* assume that this command completed successfully: */
192 status = TME_SCSI_STATUS_GOOD;
193
194 /* if there are some tape check condition flags: */
195 if (flags & ~TME_TAPE_FLAG_FIXED) {
196
197 /* there is a condition to check: */
198 status = TME_SCSI_STATUS_CHECK_CONDITION;
199
200 /* get the addressed LUN: */
201 lun = scsi_tape->tme_scsi_tape_device.tme_scsi_device_addressed_lun;
202
203 /* get the original transfer length: */
204 cdb = &scsi_tape->tme_scsi_tape_device.tme_scsi_device_cdb[0];
205 count_xfer_wanted = cdb[2];
206 count_xfer_wanted = (count_xfer_wanted << 8) | cdb[3];
207 count_xfer_wanted = (count_xfer_wanted << 8) | cdb[4];
208
209 /* set the sense: */
210 sense
211 = &scsi_tape->tme_scsi_tape_device.tme_scsi_device_sense[lun];
212
213 /* the Valid, Error Class, and Error Code values: */
214 sense->tme_scsi_device_sense_data[0]
215 = (0x80 | 0x70);
216
217 /* the Filemark, EOM, ILI, and Sense Key (NO SENSE) values: */
218 sense->tme_scsi_device_sense_data[2]
219 = (((flags & TME_TAPE_FLAG_MARK)
220 ? 0x80
221 : 0x00)
222 | ((flags & TME_TAPE_FLAG_EOM)
223 ? 0x40
224 : 0x00)
225 | ((flags & TME_TAPE_FLAG_ILI)
226 ? 0x20
227 : 0x00)
228 | 0x00);
229
230 /* set the Information Bytes (for a tape, the residue): */
231 count_xfer_wanted -= count_xfer_got;
232 sense->tme_scsi_device_sense_data[3]
233 = (count_xfer_wanted >> 24) & 0xff;
234 sense->tme_scsi_device_sense_data[4]
235 = (count_xfer_wanted >> 16) & 0xff;
236 sense->tme_scsi_device_sense_data[5]
237 = (count_xfer_wanted >> 8) & 0xff;
238 sense->tme_scsi_device_sense_data[6]
239 = (count_xfer_wanted >> 0) & 0xff;
240
241 /* there are no additional bytes: */
242 sense->tme_scsi_device_sense_data[7]
243 = 0x00;
244
245 /* this sense is valid: */
246 sense->tme_scsi_device_sense_valid
247 = TRUE;
248 }
249
250 /* done: */
251 return (status);
252 }
253
254 /* this finishes a WRITE command: */
_TME_SCSI_DEVICE_PHASE_DECL(tme_scsi_tape_target_do_write)255 _TME_SCSI_DEVICE_PHASE_DECL(tme_scsi_tape_target_do_write)
256 {
257 struct tme_scsi_tape *scsi_tape;
258 struct tme_scsi_tape_connection *conn_scsi_tape;
259 struct tme_tape_connection *conn_tape;
260 int lun;
261 unsigned long count;
262 int flags;
263 tme_uint8_t status;
264 int rc;
265
266 /* recover our tape: */
267 scsi_tape = (struct tme_scsi_tape *) scsi_device;
268
269 /* get the addressed LUN: */
270 lun = scsi_device->tme_scsi_device_addressed_lun;
271
272 /* get the tape connection: */
273 conn_scsi_tape
274 = scsi_tape->tme_scsi_tape_connections[lun];
275 conn_tape
276 = ((struct tme_tape_connection *)
277 conn_scsi_tape->tme_scsi_tape_connection.tme_tape_connection.tme_connection_other);
278
279 /* release the buffer: */
280 rc
281 = ((*conn_tape->tme_tape_connection_release)
282 (conn_tape,
283 &flags,
284 &count));
285 assert (rc == TME_OK);
286
287 /* get the status: */
288 status
289 = ((*scsi_tape->tme_scsi_tape_xfer_status)
290 (scsi_tape,
291 flags,
292 count));;
293
294 /* finish the command: */
295 tme_scsi_device_target_do_smf(scsi_device,
296 status,
297 TME_SCSI_MSG_CMD_COMPLETE);
298 }
299
300 /* this implements the tape Group 0 READ and WRITE commands: */
301 void
tme_scsi_tape_cdb_xfer0(struct tme_scsi_device * scsi_device,int read)302 tme_scsi_tape_cdb_xfer0(struct tme_scsi_device *scsi_device,
303 int read)
304 {
305 struct tme_scsi_tape *scsi_tape;
306 struct tme_scsi_tape_connection *conn_scsi_tape;
307 struct tme_tape_connection *conn_tape;
308 int lun;
309 tme_uint8_t *cdb;
310 unsigned long count_xfer;
311 unsigned int bytes_xfer;
312 int flags;
313 tme_uint8_t status;
314 int rc;
315
316 /* recover our tape: */
317 scsi_tape = (struct tme_scsi_tape *) scsi_device;
318
319 /* get the addressed LUN: */
320 lun = scsi_device->tme_scsi_device_addressed_lun;
321
322 /* get the tape connection: */
323 conn_scsi_tape
324 = scsi_tape->tme_scsi_tape_connections[lun];
325 conn_tape
326 = ((struct tme_tape_connection *)
327 conn_scsi_tape->tme_scsi_tape_connection.tme_tape_connection.tme_connection_other);
328
329 cdb = &scsi_device->tme_scsi_device_cdb[0];
330
331 /* get the fixed bit: */
332 flags = (cdb[1] & 0x01) * TME_TAPE_FLAG_FIXED;
333
334 /* get the transfer length: */
335 count_xfer = cdb[2];
336 count_xfer = (count_xfer << 8) | cdb[3];
337 count_xfer = (count_xfer << 8) | cdb[4];
338 bytes_xfer = count_xfer;
339 if (flags & TME_TAPE_FLAG_FIXED) {
340 bytes_xfer *= scsi_tape->tme_scsi_tape_block_size_current;
341 }
342
343 /* if this is a read: */
344 if (read) {
345
346 /* get the tape buffer: */
347 rc
348 = ((*conn_tape->tme_tape_connection_read)
349 (conn_tape,
350 &flags,
351 &count_xfer,
352 &scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid,
353 &scsi_device->tme_scsi_device_dma.tme_scsi_dma_out));
354 scsi_device->tme_scsi_device_dma.tme_scsi_dma_in = NULL;
355
356 /* XXX FIXME - this is a big hack. the tme_tape_connection_read
357 function always reads one or more whole tape blocks, but we
358 call it for every READ CDB, even when the initiator hasn't set
359 a block size with MODE SELECT (which allows the initiator to
360 issue reads without regard to block size - reads smaller than
361 the tape block size don't discard the remainder of a block and
362 advance to the next tape block, but instead just return
363 successive parts of the same tape block).
364
365 this entire function needs to be rewritten, to handle this mode
366 by only issuing tme_tape_connection_read calls when the block
367 buffer has been exhausted, and also honor the SILI bit. as it
368 is, this code definitely has no chance of working with a real
369 tape drive.
370
371 but to fix the immediate problem, if the read has transferred
372 some bytes with an underrun, we just pad the read out with
373 zeroes. this fixes NetBSD PR pkg/34536: */
374 if (scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid > 0
375 && scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid < bytes_xfer
376 && (flags
377 & ~(TME_TAPE_FLAG_ILI
378 | TME_TAPE_FLAG_MARK)) == 0) {
379 /* XXX this breaks const: */
380 /* XXX writing into the tape buffer breaks the tape abstraction,
381 and only works because we know that posix-tape.c has
382 allocated this buffer to be at least as big as the read we
383 requested: */
384 memset(((tme_uint8_t *)
385 (scsi_device->tme_scsi_device_dma.tme_scsi_dma_out
386 + scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid)),
387 0,
388 (bytes_xfer
389 - scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid));
390 scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid = bytes_xfer;
391 flags &= ~TME_TAPE_FLAG_ILI;
392 }
393
394 /* get the status: */
395 status
396 = ((*scsi_tape->tme_scsi_tape_xfer_status)
397 (scsi_tape,
398 flags,
399 count_xfer));
400
401 /* finish the command: */
402 tme_scsi_device_target_do_dsmf(scsi_device,
403 status,
404 TME_SCSI_MSG_CMD_COMPLETE);
405 }
406 else {
407
408 /* get the tape buffer: */
409 rc
410 = ((*conn_tape->tme_tape_connection_write)
411 (conn_tape,
412 flags,
413 count_xfer,
414 &scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid,
415 &scsi_device->tme_scsi_device_dma.tme_scsi_dma_in));
416 scsi_device->tme_scsi_device_dma.tme_scsi_dma_out = NULL;
417
418 /* enter the DATA OUT phase to transfer all of the data to be
419 written: */
420 /* XXX when in fixed-block mode, we should go a block at a time,
421 so we can report errors as soon as they happen: */
422 tme_scsi_device_target_phase(scsi_device,
423 TME_SCSI_SIGNAL_BSY
424 | TME_SCSI_PHASE_DATA_OUT);
425
426 /* when the DATA OUT phase is done, we'll write the data end
427 enter the STATUS phase: */
428 scsi_device->tme_scsi_device_phase
429 = tme_scsi_tape_target_do_write;
430 }
431
432 /* if we couldn't get the tape buffer: */
433 if (rc != TME_OK) {
434
435 /* XXX we should return MEDIUM ERROR or HARDWARE ERROR sense here: */
436 abort();
437 }
438 }
439
440 /* this implements the tape REWIND command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_rewind)441 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_rewind)
442 {
443 struct tme_scsi_tape *scsi_tape;
444 struct tme_scsi_tape_connection *conn_scsi_tape;
445 struct tme_tape_connection *conn_tape;
446 int lun;
447 int rc;
448
449 /* recover our tape: */
450 scsi_tape = (struct tme_scsi_tape *) scsi_device;
451
452 /* get the addressed LUN: */
453 lun = scsi_device->tme_scsi_device_addressed_lun;
454
455 /* get the tape connection: */
456 conn_scsi_tape
457 = scsi_tape->tme_scsi_tape_connections[lun];
458 conn_tape
459 = ((struct tme_tape_connection *)
460 conn_scsi_tape->tme_scsi_tape_connection.tme_tape_connection.tme_connection_other);
461
462 /* call out a REWIND control: */
463 rc =
464 ((*conn_tape->tme_tape_connection_control)
465 (conn_tape,
466 TME_TAPE_CONTROL_REWIND));
467 assert (rc == TME_OK);
468
469 /* finish the command: */
470 tme_scsi_device_target_do_smf(scsi_device,
471 TME_SCSI_STATUS_GOOD,
472 TME_SCSI_MSG_CMD_COMPLETE);
473 }
474
475 /* this implements the tape READ BLOCK LIMITS command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_block_limits)476 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_block_limits)
477 {
478 struct tme_scsi_tape *scsi_tape;
479 tme_uint8_t *data;
480 int lun;
481 tme_uint32_t block_size;
482
483 /* recover our tape: */
484 scsi_tape = (struct tme_scsi_tape *) scsi_device;
485
486 /* get the addressed LUN: */
487 lun = scsi_device->tme_scsi_device_addressed_lun;
488
489 data = &scsi_device->tme_scsi_device_data[0];
490
491 /* a reserved byte: */
492 data++;
493
494 /* the Maximum Block Length: */
495 block_size = scsi_tape->tme_scsi_tape_block_size_max;
496 *(data++) = (block_size >> 16) & 0xff;
497 *(data++) = (block_size >> 8) & 0xff;
498 *(data++) = (block_size >> 0) & 0xff;
499
500 /* the Minimum Block Length: */
501 block_size = scsi_tape->tme_scsi_tape_block_size_min;
502 assert (block_size > 0);
503 *(data++) = (block_size >> 8) & 0xff;
504 *(data++) = (block_size >> 0) & 0xff;
505
506 /* set the DMA pointer and length: */
507 scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid
508 = (data
509 - &scsi_device->tme_scsi_device_data[0]);
510 scsi_device->tme_scsi_device_dma.tme_scsi_dma_out
511 = &scsi_device->tme_scsi_device_data[0];
512 scsi_device->tme_scsi_device_dma.tme_scsi_dma_in
513 = NULL;
514
515 /* finish the command: */
516 tme_scsi_device_target_do_dsmf(scsi_device,
517 TME_SCSI_STATUS_GOOD,
518 TME_SCSI_MSG_CMD_COMPLETE);
519 }
520
521 /* this implements the tape Group 0 READ command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_read0)522 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_read0)
523 {
524 tme_scsi_tape_cdb_xfer0(scsi_device, TRUE);
525 }
526
527 /* this implements the tape Group 0 WRITE command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_write0)528 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_write0)
529 {
530 tme_scsi_tape_cdb_xfer0(scsi_device, FALSE);
531 }
532
533 /* this implements the tape INQUIRY command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_inquiry)534 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_inquiry)
535 {
536 int lun;
537 struct tme_scsi_device_inquiry inquiry;
538 tme_uint8_t *data;
539
540 /* get the active LUN: */
541 lun = scsi_device->tme_scsi_device_addressed_lun;
542
543 /* this is a sequential-access device: */
544 inquiry.tme_scsi_device_inquiry_type = TME_SCSI_TYPE_TAPE;
545
546 /* if this LUN is defined: */
547 inquiry.tme_scsi_device_inquiry_lun_state
548 = ((scsi_device->tme_scsi_device_luns
549 & TME_BIT(lun))
550 ? TME_SCSI_LUN_PRESENT
551 : TME_SCSI_LUN_UNSUPPORTED);
552
553 /* the device type qualifier: */
554 inquiry.tme_scsi_device_inquiry_type_qualifier = 0x00;
555
556 /* nonzero iff the LUN is removable: */
557 inquiry.tme_scsi_device_inquiry_lun_removable = TRUE;
558
559 /* the various standards versions: */
560 inquiry.tme_scsi_device_inquiry_std_ansi = 1;
561 inquiry.tme_scsi_device_inquiry_std_ecma = 1;
562 inquiry.tme_scsi_device_inquiry_std_iso = 1;
563
564 /* the response format: */
565 inquiry.tme_scsi_device_response_format = TME_SCSI_FORMAT_CCS;
566
567 /* make the inquiry data: */
568 data
569 = tme_scsi_device_make_inquiry_data(scsi_device,
570 &inquiry);
571 scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid
572 = TME_MIN((data
573 - scsi_device->tme_scsi_device_dma.tme_scsi_dma_out),
574 scsi_device->tme_scsi_device_cdb[4]);
575
576 /* finish the command: */
577 tme_scsi_device_target_do_dsmf(scsi_device,
578 TME_SCSI_STATUS_GOOD,
579 TME_SCSI_MSG_CMD_COMPLETE);
580 }
581
582 /* this implements the tape WRITE MARKS command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_write_marks)583 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_write_marks)
584 {
585 abort();
586 }
587
588 /* this implements the tape SPACE command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_space)589 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_space)
590 {
591 struct tme_scsi_tape *scsi_tape;
592 struct tme_scsi_tape_connection *conn_scsi_tape;
593 struct tme_tape_connection *conn_tape;
594 int lun;
595 tme_uint8_t *cdb;
596 tme_int32_t count;
597 int rc;
598
599 /* recover our tape: */
600 scsi_tape = (struct tme_scsi_tape *) scsi_device;
601
602 /* get the addressed LUN: */
603 lun = scsi_device->tme_scsi_device_addressed_lun;
604
605 /* get the tape connection: */
606 conn_scsi_tape
607 = scsi_tape->tme_scsi_tape_connections[lun];
608 conn_tape
609 = ((struct tme_tape_connection *)
610 conn_scsi_tape->tme_scsi_tape_connection.tme_tape_connection.tme_connection_other);
611
612 cdb = &scsi_device->tme_scsi_device_cdb[0];
613
614 /* get the signed count: */
615 count = ((tme_int8_t *) cdb)[2];
616 count = (count << 8) | cdb[3];
617 count = (count << 8) | cdb[4];
618
619 /* dispatch on the SPACE code: */
620 switch (cdb[1] & 0x03) {
621
622 /* blocks: */
623 case 0x00:
624 abort();
625
626 /* filemarks: */
627 case 0x01:
628
629 /* call out a MARK_SKIPF or MARK_SKIPR control: */
630 rc =
631 (count < 0
632 ? ((*conn_tape->tme_tape_connection_control)
633 (conn_tape,
634 TME_TAPE_CONTROL_MARK_SKIPR,
635 (unsigned int) (-count)))
636 : ((*conn_tape->tme_tape_connection_control)
637 (conn_tape,
638 TME_TAPE_CONTROL_MARK_SKIPF,
639 (unsigned int) count)));
640 assert (rc == TME_OK);
641 break;
642
643 /* sequential filemarks: */
644 case 0x02:
645 abort();
646
647 /* physical end-of-data: */
648 case 0x03:
649 abort();
650 }
651
652 /* finish the command: */
653 tme_scsi_device_target_do_smf(scsi_device,
654 TME_SCSI_STATUS_GOOD,
655 TME_SCSI_MSG_CMD_COMPLETE);
656 }
657
658 /* this processes the parameter list from a tape MODE SELECT command: */
_TME_SCSI_DEVICE_PHASE_DECL(_tme_scsi_tape_mode_select_data)659 _TME_SCSI_DEVICE_PHASE_DECL(_tme_scsi_tape_mode_select_data)
660 {
661 struct tme_scsi_tape *scsi_tape;
662 int lun;
663 struct tme_scsi_tape_connection *conn_scsi_tape;
664 struct tme_tape_connection *conn_tape;
665 const tme_uint8_t *data;
666 const tme_uint8_t *data_end;
667 tme_uint8_t status;
668 unsigned int block_descriptors;
669 tme_uint32_t blocks;
670 tme_uint32_t block_size;
671 tme_uint32_t length;
672 unsigned long sizes[3];
673 int rc;
674
675 /* recover our tape: */
676 scsi_tape = (struct tme_scsi_tape *) scsi_device;
677
678 /* get the addressed LUN: */
679 lun = scsi_device->tme_scsi_device_addressed_lun;
680
681 /* get a pointer to the first byte of data, and a pointer past the
682 last byte of data: */
683 data = &scsi_device->tme_scsi_device_data[0];
684 length = scsi_device->tme_scsi_device_cdb[4];
685 data_end = (data
686 + TME_MIN(sizeof(scsi_device->tme_scsi_device_data),
687 length));
688
689 /* assume that this command will succeed: */
690 status = TME_SCSI_STATUS_GOOD;
691
692 /* skip the two reserved bytes: */
693 data += (data < data_end);
694 data += (data < data_end);
695
696 /* we ignore the buffered mode and speed byte: */
697 data += (data < data_end);
698
699 /* get the count of bytes in block descriptors: */
700 block_descriptors
701 = (data < data_end
702 ? *(data++)
703 : 0);
704
705 /* check the block descriptors: */
706 block_size = 0;
707 for (;
708 block_descriptors >= 8;
709 block_descriptors -= 8) {
710
711 /* if this block descriptor is short: */
712 if ((data_end - data) < 8) {
713
714 /* XXX FIXME - we need to assemble a sense and return a CHECK
715 CONDITION here: */
716 abort();
717 }
718
719 /* we ignore the density code: */
720 data++;
721
722 /* get the block count: */
723 blocks = *(data++);
724 blocks = (blocks << 8) + *(data++);
725 blocks = (blocks << 8) + *(data++);
726
727 /* skip the reserved byte: */
728 data++;
729
730 /* get the block length: */
731 block_size = *(data++);
732 block_size = (block_size << 8) + *(data++);
733 block_size = (block_size << 8) + *(data++);
734
735 /* if this block descriptor doesn't describe the entire tape: */
736 if (blocks != 0) {
737
738 /* XXX FIXME - we need to assemble a sense and return a CHECK
739 CONDITION here: */
740 abort();
741 }
742
743 /* set the new current block size: */
744 scsi_tape->tme_scsi_tape_block_size_current = block_size;
745 }
746
747 /* if the parameter list was good: */
748 if (status == TME_SCSI_STATUS_GOOD) {
749
750 /* get the tape connection: */
751 conn_scsi_tape
752 = scsi_tape->tme_scsi_tape_connections[lun];
753 conn_tape
754 = ((struct tme_tape_connection *)
755 conn_scsi_tape->tme_scsi_tape_connection.tme_tape_connection.tme_connection_other);
756
757 /* set the block size: */
758 if (block_size != 0) {
759 sizes[0] = block_size;
760 sizes[1] = block_size;
761 sizes[2] = block_size;
762 }
763 else {
764 sizes[0] = scsi_tape->tme_scsi_tape_block_size_min;
765 sizes[1] = scsi_tape->tme_scsi_tape_block_size_max;
766 sizes[2] = 0;
767 }
768 rc
769 = ((*conn_tape->tme_tape_connection_control)
770 (conn_tape,
771 TME_TAPE_CONTROL_BLOCK_SIZE_SET,
772 sizes));
773 assert (rc == TME_OK);
774 }
775
776 tme_scsi_device_target_do_smf(scsi_device,
777 status,
778 TME_SCSI_MSG_CMD_COMPLETE);
779 }
780
781 /* this implements the tape MODE SELECT command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_mode_select)782 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_mode_select)
783 {
784
785 /* read in the parameter list: */
786 scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid
787 = scsi_device->tme_scsi_device_cdb[4];
788 scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid
789 = TME_MIN(scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid,
790 sizeof(scsi_device->tme_scsi_device_data));
791 scsi_device->tme_scsi_device_dma.tme_scsi_dma_in
792 = &scsi_device->tme_scsi_device_data[0];
793 scsi_device->tme_scsi_device_dma.tme_scsi_dma_out
794 = NULL;
795
796 /* transfer the parameter list: */
797 tme_scsi_device_target_phase(scsi_device,
798 (TME_SCSI_SIGNAL_BSY
799 | TME_SCSI_PHASE_DATA_OUT));
800 scsi_device->tme_scsi_device_phase
801 = _tme_scsi_tape_mode_select_data;
802 }
803
804 /* this implements the tape MODE SENSE command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_mode_sense)805 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_mode_sense)
806 {
807 struct tme_scsi_tape *scsi_tape;
808 tme_uint8_t *data;
809 tme_uint32_t blocks, block_size;
810 int lun;
811
812 /* recover our tape: */
813 scsi_tape = (struct tme_scsi_tape *) scsi_device;
814
815 /* get the addressed LUN: */
816 lun = scsi_device->tme_scsi_device_addressed_lun;
817
818 /* get the current block size: */
819 block_size = scsi_tape->tme_scsi_tape_block_size_current;
820
821 data = &scsi_device->tme_scsi_device_data[0];
822
823 /* the sense data length. we will fill this in later: */
824 data++;
825
826 /* byte 1 is the medium type: */
827 *(data++) = 0x00; /* default (only one medium type supported) */
828
829 /* byte 2 is the WP (Write Protect), Buffered Mode, and Speed: */
830 *(data++) = 0x80; /* write protected, unbuffered, default speed */
831
832 /* byte 3 is the Block Descriptor Length. we will fill this in
833 later: */
834 data++;
835
836 /* the first Block Descriptor: */
837
838 /* the Block Descriptor density code: */
839 *(data++) = 0x05; /* QIC-24 */
840
841 /* the Number of Blocks: */
842 /* XXX FIXME - we assume a 60MB tape: */
843 blocks = (60 * 1024 * 1024) / block_size;
844 *(data++) = (blocks >> 16) & 0xff;
845 *(data++) = (blocks >> 8) & 0xff;
846 *(data++) = (blocks >> 0) & 0xff;
847
848 /* a reserved byte: */
849 data++;
850
851 /* the Block Length: */
852 *(data++) = (block_size >> 16) & 0xff;
853 *(data++) = (block_size >> 8) & 0xff;
854 *(data++) = (block_size >> 0) & 0xff;
855
856 /* fill in the Block Descriptor Length: */
857 scsi_device->tme_scsi_device_data[3]
858 = (data - &scsi_device->tme_scsi_device_data[4]);
859
860 /* there are no vendor-unique bytes or mode pages: */
861
862 /* fill in the sense data length: */
863 scsi_device->tme_scsi_device_data[0]
864 = (data - &scsi_device->tme_scsi_device_data[1]);
865
866 /* set the DMA pointer and length: */
867 scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid
868 = TME_MIN((data
869 - &scsi_device->tme_scsi_device_data[0]),
870 scsi_device->tme_scsi_device_cdb[4]);
871 scsi_device->tme_scsi_device_dma.tme_scsi_dma_out
872 = &scsi_device->tme_scsi_device_data[0];
873 scsi_device->tme_scsi_device_dma.tme_scsi_dma_in
874 = NULL;
875
876 /* finish the command: */
877 tme_scsi_device_target_do_dsmf(scsi_device,
878 TME_SCSI_STATUS_GOOD,
879 TME_SCSI_MSG_CMD_COMPLETE);
880 }
881
882 /* this implements the tape LOAD/UNLOAD command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_load_unload)883 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_load_unload)
884 {
885 /* XXX TBD */
886
887 /* finish the command: */
888 tme_scsi_device_target_do_smf(scsi_device,
889 TME_SCSI_STATUS_GOOD,
890 TME_SCSI_MSG_CMD_COMPLETE);
891 }
892
893 /* this implements the tape PREVENT/ALLOW command: */
_TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_prevent_allow)894 _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_tape_cdb_prevent_allow)
895 {
896 /* XXX TBD */
897
898 /* finish the command: */
899 tme_scsi_device_target_do_smf(scsi_device,
900 TME_SCSI_STATUS_GOOD,
901 TME_SCSI_MSG_CMD_COMPLETE);
902 }
903
904 /* the tape control handler: */
905 #ifdef HAVE_STDARG_H
_tme_scsi_tape_control(struct tme_tape_connection * conn_tape,unsigned int control,...)906 static int _tme_scsi_tape_control(struct tme_tape_connection *conn_tape,
907 unsigned int control,
908 ...)
909 #else /* HAVE_STDARG_H */
910 static int _tme_scsi_tape_control(conn_tape, control, va_alist)
911 struct tme_tape_connection *conn_tape;
912 unsigned int control;
913 va_dcl
914 #endif /* HAVE_STDARG_H */
915 {
916 struct tme_scsi_tape *scsi_tape;
917 struct tme_scsi_tape_connection *conn_scsi_tape;
918 va_list control_args;
919
920 /* recover our data structures: */
921 conn_scsi_tape = (struct tme_scsi_tape_connection *) conn_tape;
922 scsi_tape = (struct tme_scsi_tape *) conn_tape->tme_tape_connection.tme_connection_element->tme_element_private;
923
924 /* lock the mutex: */
925 tme_mutex_lock(&scsi_tape->tme_scsi_tape_mutex);
926
927 /* start the variable arguments: */
928 #ifdef HAVE_STDARG_H
929 va_start(control_args, control);
930 #else /* HAVE_STDARG_H */
931 va_start(control_args);
932 #endif /* HAVE_STDARG_H */
933
934 /* dispatch on the sequence type: */
935 switch (control) {
936
937 case TME_TAPE_CONTROL_LOAD:
938 /* a tape has been loaded: */
939 conn_scsi_tape->tme_scsi_tape_connection_flags
940 = (conn_scsi_tape->tme_scsi_tape_connection_flags
941 | (TME_SCSI_TAPE_FLAG_LOADED
942 | TME_SCSI_TAPE_FLAG_ATTENTION));
943 break;
944
945 case TME_TAPE_CONTROL_UNLOAD:
946 /* a tape has been unloaded: */
947 conn_scsi_tape->tme_scsi_tape_connection_flags
948 = ((conn_scsi_tape->tme_scsi_tape_connection_flags
949 & ~TME_SCSI_TAPE_FLAG_LOADED)
950 | TME_SCSI_TAPE_FLAG_ATTENTION);
951 break;
952
953 abort();
954
955 case TME_TAPE_CONTROL_DENSITY_GET:
956 abort();
957
958 case TME_TAPE_CONTROL_DENSITY_SET:
959 abort();
960
961 case TME_TAPE_CONTROL_BLOCK_SIZE_GET:
962 abort();
963
964 case TME_TAPE_CONTROL_BLOCK_SIZE_SET:
965 abort();
966
967 case TME_TAPE_CONTROL_REWIND:
968 case TME_TAPE_CONTROL_MARK_WRITE:
969 case TME_TAPE_CONTROL_MARK_SKIPF:
970 case TME_TAPE_CONTROL_MARK_SKIPR:
971 default:
972 abort();
973 }
974
975 /* end the variable arguments: */
976 va_end(control_args);
977
978 /* unlock the mutex: */
979 tme_mutex_unlock(&scsi_tape->tme_scsi_tape_mutex);
980
981 return (TME_OK);
982 }
983
984 /* this breaks a connection: */
985 static int
_tme_scsi_tape_connection_break(struct tme_connection * conn,unsigned int state)986 _tme_scsi_tape_connection_break(struct tme_connection *conn,
987 unsigned int state)
988 {
989 abort();
990 }
991
992 /* this makes a new tape connection: */
993 static int
_tme_scsi_tape_connection_make(struct tme_connection * conn,unsigned int state)994 _tme_scsi_tape_connection_make(struct tme_connection *conn,
995 unsigned int state)
996 {
997 struct tme_scsi_tape *scsi_tape;
998 struct tme_scsi_tape_connection *conn_scsi_tape;
999 struct tme_tape_connection *conn_tape;
1000 int lun;
1001 int loaded;
1002 int rc;
1003
1004 /* both sides must be tape connections: */
1005 assert (conn->tme_connection_type == TME_CONNECTION_TAPE);
1006 assert (conn->tme_connection_other->tme_connection_type == TME_CONNECTION_TAPE);
1007
1008 /* recover our data structures: */
1009 scsi_tape = conn->tme_connection_element->tme_element_private;
1010 conn_scsi_tape = (struct tme_scsi_tape_connection *) conn;
1011
1012 /* we're always set up to answer calls across the connection,
1013 so we only have to do work when the connection has gone full,
1014 namely taking the other side of the connection: */
1015 if (state == TME_CONNECTION_FULL) {
1016
1017 /* lock the mutex: */
1018 tme_mutex_lock(&scsi_tape->tme_scsi_tape_mutex);
1019
1020 /* make this tape connection: */
1021 lun = conn_scsi_tape->tme_scsi_tape_connection_lun;
1022 assert (scsi_tape->tme_scsi_tape_connections[lun]
1023 == NULL);
1024 scsi_tape->tme_scsi_tape_connections[lun]
1025 = conn_scsi_tape;
1026 scsi_tape->tme_scsi_tape_device.tme_scsi_device_luns
1027 |= (1 << lun);
1028
1029 /* call any type-specific connection function: */
1030 if (scsi_tape->tme_scsi_tape_connected != NULL) {
1031 (*scsi_tape->tme_scsi_tape_connected)(scsi_tape, lun);
1032 }
1033
1034 /* call out a LOAD control to see if the tape is currently loaded: */
1035 conn_tape
1036 = ((struct tme_tape_connection *)
1037 conn_scsi_tape->tme_scsi_tape_connection.tme_tape_connection.tme_connection_other);
1038 rc =
1039 ((*conn_tape->tme_tape_connection_control)
1040 (conn_tape,
1041 TME_TAPE_CONTROL_LOAD,
1042 &loaded));
1043 assert (rc == TME_OK);
1044 conn_scsi_tape->tme_scsi_tape_connection_flags
1045 = (loaded
1046 ? (TME_SCSI_TAPE_FLAG_LOADED
1047 | TME_SCSI_TAPE_FLAG_ATTENTION)
1048 : 0);
1049
1050 /* unlock the mutex: */
1051 tme_mutex_unlock(&scsi_tape->tme_scsi_tape_mutex);
1052 }
1053
1054 return (TME_OK);
1055 }
1056
1057 /* this returns the new connections possible: */
1058 static int
_tme_scsi_tape_connections_new(struct tme_element * element,const char * const * args,struct tme_connection ** _conns,char ** _output)1059 _tme_scsi_tape_connections_new(struct tme_element *element,
1060 const char * const *args,
1061 struct tme_connection **_conns,
1062 char **_output)
1063 {
1064 struct tme_scsi_tape *scsi_tape;
1065 struct tme_scsi_tape_connection *conn_scsi_tape;
1066 struct tme_tape_connection *conn_tape;
1067 struct tme_connection *conn;
1068 int lun;
1069 int arg_i;
1070 int usage;
1071 int rc;
1072
1073 /* recover our device: */
1074 scsi_tape = (struct tme_scsi_tape *) element->tme_element_private;
1075
1076 /* check our arguments: */
1077 lun = -1;
1078 arg_i = 1;
1079 usage = FALSE;
1080
1081 /* loop reading our arguments: */
1082 for (;;) {
1083
1084 /* the LUN to attach to: */
1085 if (TME_ARG_IS(args[arg_i + 0], "lun")
1086 && lun < 0
1087 && (lun = tme_scsi_lun_parse(args[arg_i + 1])) >= 0
1088 && lun < TME_SCSI_DEVICE_LUN_COUNT
1089 && scsi_tape->tme_scsi_tape_connections[lun] == NULL) {
1090 arg_i += 2;
1091 }
1092
1093 /* if we've run out of arguments: */
1094 else if (args[arg_i + 0] == NULL) {
1095 break;
1096 }
1097
1098 /* this is a bad argument: */
1099 else {
1100 tme_output_append_error(_output,
1101 "%s %s, ",
1102 args[arg_i],
1103 _("unexpected"));
1104 usage = TRUE;
1105 break;
1106 }
1107 }
1108
1109 if (usage) {
1110 tme_output_append_error(_output,
1111 "%s %s [ lun %s ]",
1112 _("usage:"),
1113 args[0],
1114 _("LOGICAL-UNIT"));
1115 return (EINVAL);
1116 }
1117
1118 /* return any SCSI device SCSI connection: */
1119 rc = tme_scsi_device_connections_new(element,
1120 args,
1121 _conns,
1122 _output);
1123 if (rc != TME_OK) {
1124 return (rc);
1125 }
1126
1127 /* if we don't have a particular lun, see if there is a free lun.
1128 if there isn't a free lun, return now: */
1129 if (lun < 0) {
1130 for (lun = 0;
1131 lun < TME_SCSI_DEVICE_LUN_COUNT;
1132 lun++) {
1133 if (scsi_tape->tme_scsi_tape_connections[lun] == NULL) {
1134 break;
1135 }
1136 }
1137 if (lun == TME_SCSI_DEVICE_LUN_COUNT) {
1138 return (TME_OK);
1139 }
1140 }
1141
1142 /* create our side of a tape connection: */
1143 conn_scsi_tape = tme_new0(struct tme_scsi_tape_connection, 1);
1144 conn_tape = &conn_scsi_tape->tme_scsi_tape_connection;
1145 conn = &conn_tape->tme_tape_connection;
1146
1147 /* fill in the generic connection: */
1148 conn->tme_connection_next = *_conns;
1149 conn->tme_connection_type = TME_CONNECTION_TAPE;
1150 conn->tme_connection_score = tme_tape_connection_score;
1151 conn->tme_connection_make = _tme_scsi_tape_connection_make;
1152 conn->tme_connection_break = _tme_scsi_tape_connection_break;
1153
1154 /* fill in the tape connection: */
1155 conn_tape->tme_tape_connection_control = _tme_scsi_tape_control;
1156
1157 /* fill in the internal tape connection: */
1158 conn_scsi_tape->tme_scsi_tape_connection_lun = lun;
1159
1160 /* return the connection side possibility: */
1161 *_conns = conn;
1162 return (TME_OK);
1163 }
1164
1165 /* the new SCSI tape function: */
TME_ELEMENT_SUB_NEW_DECL(tme_scsi,tape)1166 TME_ELEMENT_SUB_NEW_DECL(tme_scsi,tape) {
1167 int id;
1168 const char *tape_type;
1169 const char *vendor;
1170 const char *product;
1171 const char *revision;
1172 struct tme_scsi_tape *scsi_tape;
1173 struct tme_scsi_device *scsi_device;
1174 int arg_i;
1175 int usage;
1176 unsigned int tape_list_i;
1177 int (*tape_init) _TME_P((struct tme_scsi_tape *));
1178 int rc;
1179
1180 /* check our arguments: */
1181 id = -1;
1182 tape_type = NULL;
1183 vendor = NULL;
1184 product = NULL;
1185 revision = NULL;
1186 arg_i = 1;
1187 usage = FALSE;
1188
1189 /* loop reading our arguments: */
1190 for (;;) {
1191
1192 /* the SCSI ID: */
1193 if (TME_ARG_IS(args[arg_i], "id")
1194 && id < 0
1195 && (id = tme_scsi_id_parse(args[arg_i + 1])) >= 0) {
1196 arg_i += 2;
1197 }
1198
1199 /* the tape type: */
1200 else if (TME_ARG_IS(args[arg_i], "type")
1201 && tape_type == NULL
1202 && args[arg_i + 1] != NULL) {
1203 tape_type = args[arg_i + 1];
1204 arg_i += 2;
1205 }
1206
1207 /* any inquiry vendor, product, or revision: */
1208 else if (TME_ARG_IS(args[arg_i], "vendor")
1209 && vendor == NULL
1210 && args[arg_i + 1] != NULL) {
1211 vendor = args[arg_i + 1];
1212 arg_i += 2;
1213 }
1214 else if (TME_ARG_IS(args[arg_i], "product")
1215 && product == NULL
1216 && args[arg_i + 1] != NULL) {
1217 product = args[arg_i + 1];
1218 arg_i += 2;
1219 }
1220 else if (TME_ARG_IS(args[arg_i], "revision")
1221 && revision == NULL
1222 && args[arg_i + 1] != NULL) {
1223 revision = args[arg_i + 1];
1224 arg_i += 2;
1225 }
1226
1227 /* if we've run out of arguments: */
1228 else if (args[arg_i + 0] == NULL) {
1229
1230 /* we must have been given an ID and a type: */
1231 if (id < 0
1232 || tape_type == NULL) {
1233 usage = TRUE;
1234 }
1235 break;
1236 }
1237
1238 /* this is a bad argument: */
1239 else {
1240 tme_output_append_error(_output,
1241 "%s %s",
1242 args[arg_i],
1243 _("unexpected"));
1244 usage = TRUE;
1245 break;
1246 }
1247 }
1248
1249 if (usage) {
1250 tme_output_append_error(_output,
1251 "%s %s id %s type %s [ vendor %s ] [ product %s ] [ revision %s ]",
1252 _("usage:"),
1253 args[0],
1254 _("TYPE"),
1255 _("ID"),
1256 _("VENDOR"),
1257 _("PRODUCT"),
1258 _("REVISION"));
1259 return (EINVAL);
1260 }
1261
1262 /* make sure that this tape type is known: */
1263 tape_init = NULL;
1264 for (tape_list_i = 0;
1265 tape_list_i < TME_ARRAY_ELS(_tme_scsi_tape_list);
1266 tape_list_i++) {
1267 if (!strcmp(_tme_scsi_tape_list[tape_list_i]._tme_scsi_tape_list_type,
1268 tape_type)) {
1269 tape_init = _tme_scsi_tape_list[tape_list_i]._tme_scsi_tape_list_init;
1270 break;
1271 }
1272 }
1273 if (tape_init == NULL) {
1274 tme_output_append_error(_output, "%s", tape_type);
1275 return (ENOENT);
1276 }
1277
1278 /* start the tape structure: */
1279 scsi_tape = tme_new0(struct tme_scsi_tape, 1);
1280 scsi_tape->tme_scsi_tape_element = element;
1281 scsi_tape->tme_scsi_tape_type = tme_strdup(tape_type);
1282
1283 /* initialize the generic SCSI device structure: */
1284 scsi_device = &scsi_tape->tme_scsi_tape_device;
1285 rc = tme_scsi_device_new(scsi_device, id);
1286 assert (rc == TME_OK);
1287
1288 scsi_device->tme_scsi_device_vendor
1289 = tme_strdup((vendor == NULL)
1290 ? "TME"
1291 : vendor);
1292 scsi_device->tme_scsi_device_product
1293 = tme_strdup((product == NULL)
1294 ? "TAPE"
1295 : product);
1296 scsi_device->tme_scsi_device_revision
1297 = tme_strdup((revision == NULL)
1298 ? "0000"
1299 : revision);
1300
1301 /* set the commands for sequential-access devices: */
1302 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1303 TME_SCSI_CDB_INQUIRY,
1304 tme_scsi_tape_cdb_inquiry);
1305 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1306 TME_SCSI_CDB_TAPE_REWIND,
1307 tme_scsi_tape_cdb_rewind);
1308 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1309 TME_SCSI_CDB_TAPE_BLOCK_LIMITS,
1310 tme_scsi_tape_cdb_block_limits);
1311 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1312 TME_SCSI_CDB_TAPE_READ0,
1313 tme_scsi_tape_cdb_read0);
1314 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1315 TME_SCSI_CDB_TAPE_WRITE0,
1316 tme_scsi_tape_cdb_write0);
1317 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1318 TME_SCSI_CDB_TAPE_WRITE_MARKS,
1319 tme_scsi_tape_cdb_write_marks);
1320 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1321 TME_SCSI_CDB_TAPE_SPACE,
1322 tme_scsi_tape_cdb_space);
1323 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1324 TME_SCSI_CDB_TAPE_MODE_SELECT,
1325 tme_scsi_tape_cdb_mode_select);
1326 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1327 TME_SCSI_CDB_TAPE_MODE_SENSE,
1328 tme_scsi_tape_cdb_mode_sense);
1329 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1330 TME_SCSI_CDB_TAPE_LOAD_UNLOAD,
1331 tme_scsi_tape_cdb_load_unload);
1332 TME_SCSI_DEVICE_DO_CDB(scsi_device,
1333 TME_SCSI_CDB_TAPE_PREVENT_ALLOW,
1334 tme_scsi_tape_cdb_prevent_allow);
1335
1336 /* there is no type-specific connected function: */
1337 scsi_tape->tme_scsi_tape_connected = NULL;
1338
1339 /* use the default transfer status function: */
1340 scsi_tape->tme_scsi_tape_xfer_status
1341 = tme_scsi_tape_xfer_status;
1342
1343 /* use the default tape LUN addresser: */
1344 scsi_device->tme_scsi_device_address_lun
1345 = tme_scsi_tape_address_lun_aware;
1346
1347 /* call the type-specific initialization function: */
1348 rc = (*tape_init)(scsi_tape);
1349 assert (rc == TME_OK);
1350
1351 /* fill the element: */
1352 element->tme_element_private = scsi_tape;
1353 element->tme_element_connections_new = _tme_scsi_tape_connections_new;
1354
1355 return (TME_OK);
1356 }
1357