FreeBSD/Linux Kernel Cross Reference
sys/scsi/rz_tape.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: rz_tape.c,v $
29 * Revision 2.16 93/05/10 21:22:44 rvb
30 * Added GET_SIZE ioctl.
31 * Fixed log and a couple of comments.
32 * [93/04/09 af]
33 *
34 * Revision 2.15 93/01/14 17:55:39 danner
35 * Changed to use common strategy routine.
36 * Handle fixed tape errors better (idall is happy).
37 * 64bit cleanup.
38 * [92/12/01 af]
39 *
40 * Revision 2.14 92/08/03 17:54:05 jfriedl
41 * removed silly prototypes
42 * [92/08/02 jfriedl]
43 *
44 * Revision 2.13 92/05/21 17:23:52 jfriedl
45 * Cleanup to quiet gcc warnings.
46 * [92/05/18 jfriedl]
47 *
48 * Revision 2.12 92/04/06 23:23:09 rpd
49 * Use scsi_print_sense_data where applicable.
50 * [92/04/06 af]
51 *
52 * Revision 2.11 92/02/23 22:44:37 elf
53 * Changed the interface of a number of functions not to
54 * require the scsi_softc pointer any longer. It was
55 * mostly unused, now it can be found via tgt->masterno.
56 * [92/02/22 19:30:10 af]
57 *
58 * Revision 2.10 91/10/09 16:17:19 af
59 * Revision 2.9.1.2 91/09/01 17:16:50 af
60 * Zero io_error before using the ior.
61 * Revision 2.9.1.1 91/08/29 18:08:50 af
62 * Fixed to compile again under 2.5.
63 *
64 * Revision 2.9 91/08/24 12:28:15 af
65 * Flag tapes as exclusive open, Spl defs, now we
66 * understand fixed-size tapes (QIC-11), multiP locks.
67 * [91/08/02 03:56:41 af]
68 *
69 * Cast args for bcopy.
70 *
71 * Revision 2.8 91/06/25 20:56:33 rpd
72 * Tweaks to make gcc happy.
73 *
74 * Revision 2.7 91/06/19 11:57:12 rvb
75 * File moved here from mips/PMAX since it is now "MI" code, also
76 * used by Vax3100 and soon -- the omron luna88k.
77 * [91/06/04 rvb]
78 *
79 * Revision 2.6 91/05/14 17:27:00 mrt
80 * Correcting copyright
81 *
82 * Revision 2.5 91/05/13 06:34:29 af
83 * Do not say we failed to bspfile when the target really was
84 * only busy.
85 * Retrieve from mode_sense speed, density and writeprotect info.
86 * Deal with targets that are busy, note when we get confused due
87 * to a scsi bus reset. Set speed and density if user asks to.
88 * Generally, made it work properly [it passes Rudy's tests].
89 * Tapes really work now.
90 *
91 * Revision 2.4 91/02/05 17:44:01 mrt
92 * Added author notices
93 * [91/02/04 11:17:11 mrt]
94 *
95 * Changed to use new Mach copyright
96 * [91/02/02 12:15:49 mrt]
97 *
98 * Revision 2.3 90/12/05 23:34:04 af
99 * Mild attempt to get it working. Needs lots of work still.
100 * [90/12/03 23:34:27 af]
101 *
102 * Revision 2.1.1.1 90/11/01 03:44:11 af
103 * Created.
104 * [90/10/21 af]
105 */
106 /*
107 * File: rz_tape.c
108 * Author: Alessandro Forin, Carnegie Mellon University
109 * Date: 10/90
110 *
111 * Top layer of the SCSI driver: interface with the MI.
112 * This file contains operations specific to TAPE-like devices.
113 */
114
115 #include <mach/std_types.h>
116 #include <scsi/compat_30.h>
117
118 #include <sys/ioctl.h>
119 #ifdef MACH_KERNEL
120 #include <device/tape_status.h>
121 #else /*MACH_KERNEL*/
122 #include <mips/PMAX/tape_status.h>
123 #endif /*MACH_KERNEL*/
124
125 #include <scsi/scsi.h>
126 #include <scsi/scsi_defs.h>
127 #include <scsi/rz.h>
128
129
130
131 void sctape_start(); /* forward */
132
133 int scsi_tape_timeout = 5*60; /* secs, tk50 is slow when positioning far apart */
134
135 int sctape_open(tgt, req)
136 target_info_t *tgt;
137 io_req_t req;
138 {
139 io_return_t ret;
140 io_req_t ior;
141 int i;
142 scsi_mode_sense_data_t *mod;
143
144 #ifdef MACH_KERNEL
145 req->io_device->flag |= D_EXCL_OPEN;
146 #endif /*MACH_KERNEL*/
147
148 /* Preferably allow tapes to disconnect */
149 if (BGET(scsi_might_disconnect,(unsigned char)tgt->masterno,tgt->target_id))
150 BSET(scsi_should_disconnect,(unsigned char)tgt->masterno,tgt->target_id);
151
152 /*
153 * Dummy ior for proper sync purposes
154 */
155 io_req_alloc(ior,0);
156 ior->io_count = 0;
157
158 /*
159 * Do a mode sense first, some drives might be picky
160 * about changing params [even if the standard might
161 * say otherwise, sigh.]
162 */
163 do {
164 ior->io_op = IO_INTERNAL;
165 ior->io_next = 0;
166 ior->io_error = 0;
167 ret = scsi_mode_sense(tgt, 0, 32, ior);
168 } while (ret == SCSI_RET_RETRY);
169
170 mod = (scsi_mode_sense_data_t *)tgt->cmd_ptr;
171 if (scsi_debug) {
172 int p[5];
173 bcopy((char*)mod, (char*)p, sizeof(p));
174 printf("[modsns(%x): x%x x%x x%x x%x x%x]", ret,
175 p[0], p[1], p[2], p[3], p[4]);
176 }
177 if (ret == SCSI_RET_DEVICE_DOWN)
178 goto out;
179 if (ret == SCSI_RET_SUCCESS) {
180 tgt->dev_info.tape.read_only = mod->wp;
181 tgt->dev_info.tape.speed = mod->speed;
182 tgt->dev_info.tape.density = mod->bdesc[0].density_code;
183 } /* else they all default sensibly, using zeroes */
184
185 /* Some tapes have limits on record-length */
186 again:
187 ior->io_op = IO_INTERNAL;
188 ior->io_next = 0;
189 ior->io_error = 0;
190 ret = scsi_read_block_limits( tgt, ior);
191 if (ret == SCSI_RET_RETRY) goto again;
192 if (!ior->io_error && (ret == SCSI_RET_SUCCESS)) {
193 scsi_blimits_data_t *lim;
194 int maxl;
195
196 lim = (scsi_blimits_data_t *) tgt->cmd_ptr;
197
198 tgt->block_size = (lim->minlen_msb << 8) |
199 lim->minlen_lsb;
200
201 maxl = (lim->maxlen_msb << 16) |
202 (lim->maxlen_sb << 8) |
203 lim->maxlen_lsb;
204 if (maxl == 0)
205 maxl = (unsigned)-1;
206 tgt->dev_info.tape.maxreclen = maxl;
207 tgt->dev_info.tape.fixed_size = (maxl == tgt->block_size);
208 } else {
209 /* let the user worry about it */
210 /* default: tgt->block_size = 1; */
211 tgt->dev_info.tape.maxreclen = (unsigned)-1;
212 tgt->dev_info.tape.fixed_size = FALSE;
213 }
214
215 /* Try hard to do a mode select */
216 for (i = 0; i < 5; i++) {
217 ior->io_op = IO_INTERNAL;
218 ior->io_error = 0;
219 ret = sctape_mode_select(tgt, 0, 0, FALSE, ior);
220 if (ret == SCSI_RET_SUCCESS)
221 break;
222 }
223 if (scsi_watchdog_period < scsi_tape_timeout)
224 scsi_watchdog_period += scsi_tape_timeout;
225
226 #if 0 /* this might imply rewind, which we do not want, although yes, .. */
227 /* we want the tape loaded */
228 ior->io_op = IO_INTERNAL;
229 ior->io_next = 0;
230 ior->io_error = 0;
231 ret = scsi_start_unit(tgt, SCSI_CMD_SS_START, ior);
232 #endif
233 req->io_device->bsize = tgt->block_size;
234 out:
235 io_req_free(ior);
236 return ret;
237 }
238
239
240 io_return_t sctape_close(tgt)
241 target_info_t *tgt;
242 {
243 io_return_t ret = SCSI_RET_SUCCESS;
244 io_req_t ior;
245
246 /*
247 * Dummy ior for proper sync purposes
248 */
249 io_req_alloc(ior,0);
250 ior->io_op = IO_INTERNAL;
251 ior->io_next = 0;
252 ior->io_count = 0;
253
254 if (tgt->ior) printf("TAPE: Close with pending requests ?? \n");
255
256 /* write a filemark if we xtnded/truncated the tape */
257 if (tgt->flags & TGT_WRITTEN_TO) {
258 tgt->ior = ior;
259 ior->io_error = 0;
260 ret = scsi_write_filemarks(tgt, 2, ior);
261 if (ret != SCSI_RET_SUCCESS)
262 printf("%s%d: wfmark failed x%x\n",
263 (*tgt->dev_ops->driver_name)(TRUE), tgt->target_id, ret);
264 /*
265 * Don't bother repositioning if we'll rewind it
266 */
267 if (tgt->flags & TGT_REWIND_ON_CLOSE)
268 goto rew;
269 retry:
270 tgt->ior = ior;
271 ior->io_op = IO_INTERNAL;
272 ior->io_error = 0;
273 ior->io_next = 0;
274 ret = scsi_space(tgt, SCSI_CMD_SP_FIL, -1, ior);
275 if (ret != SCSI_RET_SUCCESS) {
276 if (ret == SCSI_RET_RETRY) {
277 timeout(wakeup, tgt, hz);
278 await(tgt);
279 goto retry;
280 }
281 printf("%s%d: bspfile failed x%x\n",
282 (*tgt->dev_ops->driver_name)(TRUE), tgt->target_id, ret);
283 }
284 }
285 rew:
286 if (tgt->flags & TGT_REWIND_ON_CLOSE) {
287 /* Rewind tape */
288 ior->io_error = 0;
289 ior->io_op = IO_INTERNAL;
290 ior->io_error = 0;
291 tgt->ior = ior;
292 (void) scsi_rewind(tgt, ior, FALSE);
293 iowait(ior);
294 if (tgt->done == SCSI_RET_RETRY) {
295 timeout(wakeup, tgt, 5*hz);
296 await(tgt);
297 goto rew;
298 }
299 }
300 io_req_free(ior);
301
302 tgt->flags &= ~(TGT_ONLINE|TGT_WRITTEN_TO|TGT_REWIND_ON_CLOSE);
303 return ret;
304 }
305
306 int sctape_strategy(ior)
307 register io_req_t ior;
308 {
309 target_info_t *tgt;
310 register int i = ior->io_unit;
311
312 tgt = scsi_softc[rzcontroller(i)]->target[rzslave(i)];
313
314 if (((ior->io_op & IO_READ) == 0) &&
315 tgt->dev_info.tape.read_only) {
316 ior->io_error = D_INVALID_OPERATION;
317 ior->io_op |= IO_ERROR;
318 ior->io_residual = ior->io_count;
319 iodone(ior);
320 return ior->io_error;
321 }
322
323 return rz_simpleq_strategy( ior, sctape_start);
324 }
325
326 static void
327 do_residue(ior, sns, bsize)
328 io_req_t ior;
329 scsi_sense_data_t *sns;
330 int bsize;
331 {
332 int residue;
333
334 /* Not an error situation */
335 ior->io_error = 0;
336 ior->io_op &= ~IO_ERROR;
337
338 if (!sns->addr_valid) {
339 ior->io_residual = ior->io_count;
340 return;
341 }
342
343 residue = sns->u.xtended.info0 << 24 |
344 sns->u.xtended.info1 << 16 |
345 sns->u.xtended.info2 << 8 |
346 sns->u.xtended.info3;
347 /* fixed ? */
348 residue *= bsize;
349 /*
350 * NOTE: residue == requested - actual
351 * We only care if > 0
352 */
353 if (residue < 0) residue = 0;/* sanity */
354 ior->io_residual += residue;
355 }
356
357 void sctape_start( tgt, done)
358 target_info_t *tgt;
359 boolean_t done;
360 {
361 io_req_t head, ior = tgt->ior;
362
363 if (ior == 0)
364 return;
365
366 if (done) {
367
368 /* see if we must retry */
369 if ((tgt->done == SCSI_RET_RETRY) &&
370 ((ior->io_op & IO_INTERNAL) == 0)) {
371 delay(1000000);/*XXX*/
372 goto start;
373 } else
374 /* got a bus reset ? ouch, that hurts */
375 if (tgt->done == (SCSI_RET_ABORTED|SCSI_RET_RETRY)) {
376 /*
377 * we really cannot retry because the tape position
378 * is lost.
379 */
380 printf("Lost tape position\n");
381 ior->io_error = D_IO_ERROR;
382 ior->io_op |= IO_ERROR;
383 } else
384
385 /* check completion status */
386
387 if (tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) {
388 scsi_sense_data_t *sns;
389
390 ior->io_op = ior->io_temporary;
391 ior->io_error = D_IO_ERROR;
392 ior->io_op |= IO_ERROR;
393
394 sns = (scsi_sense_data_t *)tgt->cmd_ptr;
395
396 if (scsi_debug)
397 scsi_print_sense_data(sns);
398
399 if (scsi_check_sense_data(tgt, sns)) {
400 if (sns->u.xtended.ili) {
401 if (ior->io_op & IO_READ) {
402 do_residue(ior, sns, tgt->block_size);
403 if (scsi_debug)
404 printf("Tape Short Read (%d)\n",
405 ior->io_residual);
406 }
407 } else if (sns->u.xtended.eom) {
408 do_residue(ior, sns, tgt->block_size);
409 if (scsi_debug)
410 printf("End of Physical Tape!\n");
411 } else if (sns->u.xtended.fm) {
412 do_residue(ior, sns, tgt->block_size);
413 if (scsi_debug)
414 printf("File Mark\n");
415 }
416 }
417 }
418
419 else if (tgt->done != SCSI_RET_SUCCESS) {
420
421 if (tgt->done == SCSI_RET_NEED_SENSE) {
422
423 ior->io_temporary = ior->io_op;
424 ior->io_op = IO_INTERNAL;
425 if (scsi_debug)
426 printf("[NeedSns x%x x%x]", ior->io_residual, ior->io_count);
427 scsi_request_sense(tgt, ior, 0);
428 return;
429
430 } else if (tgt->done == SCSI_RET_RETRY) {
431 /* only retry here READs and WRITEs */
432 if ((ior->io_op & IO_INTERNAL) == 0) {
433 ior->io_residual = 0;
434 goto start;
435 } else{
436 ior->io_error = D_WOULD_BLOCK;
437 ior->io_op |= IO_ERROR;
438 }
439 } else {
440 ior->io_error = D_IO_ERROR;
441 ior->io_op |= IO_ERROR;
442 }
443 }
444
445 if (scsi_debug)
446 printf("[Resid x%x]", ior->io_residual);
447
448 /* dequeue next one */
449 head = ior;
450
451 simple_lock(&tgt->target_lock);
452 ior = head->io_next;
453 tgt->ior = ior;
454 if (ior)
455 ior->io_prev = head->io_prev;
456 simple_unlock(&tgt->target_lock);
457
458 iodone(head);
459
460 if (ior == 0)
461 return;
462 }
463 ior->io_residual = 0;
464 start:
465 if (ior->io_op & IO_READ) {
466 tgt->flags &= ~TGT_WRITTEN_TO;
467 sctape_read( tgt, ior );
468 } else if ((ior->io_op & IO_INTERNAL) == 0) {
469 tgt->flags |= TGT_WRITTEN_TO;
470 sctape_write( tgt, ior );
471 }
472 }
473
474 io_return_t
475 sctape_get_status( dev, tgt, flavor, status, status_count)
476 int dev;
477 target_info_t *tgt;
478 dev_flavor_t flavor;
479 dev_status_t status;
480 natural_t *status_count;
481 {
482 switch (flavor) {
483 case DEV_GET_SIZE:
484
485 status[DEV_GET_SIZE_DEVICE_SIZE] = 0;
486 status[DEV_GET_SIZE_RECORD_SIZE] = tgt->block_size;
487 *status_count = DEV_GET_SIZE_COUNT;
488 break;
489 case TAPE_STATUS: {
490 struct tape_status *ts = (struct tape_status *) status;
491
492 ts->mt_type = MT_ISSCSI;
493 ts->speed = tgt->dev_info.tape.speed;
494 ts->density = tgt->dev_info.tape.density;
495 ts->flags = (tgt->flags & TGT_REWIND_ON_CLOSE) ?
496 TAPE_FLG_REWIND : 0;
497 if (tgt->dev_info.tape.read_only)
498 ts->flags |= TAPE_FLG_WP;
499 #ifdef MACH_KERNEL
500 *status_count = TAPE_STATUS_COUNT;
501 #endif
502
503 break;
504 }
505 /* U*x compat */
506 case MTIOCGET: {
507 struct mtget *g = (struct mtget *) status;
508
509 bzero(g, sizeof(struct mtget));
510 g->mt_type = 0x7; /* Ultrix compat */
511 #ifdef MACH_KERNEL
512 *status_count = sizeof(struct mtget)/sizeof(int);
513 #endif
514 break;
515 }
516 default:
517 return D_INVALID_OPERATION;
518 }
519 return D_SUCCESS;
520 }
521
522 io_return_t
523 sctape_set_status( dev, tgt, flavor, status, status_count)
524 int dev;
525 target_info_t *tgt;
526 dev_flavor_t flavor;
527 dev_status_t status;
528 natural_t status_count;
529 {
530 scsi_ret_t ret;
531
532 switch (flavor) {
533 case TAPE_STATUS: {
534 struct tape_status *ts = (struct tape_status *) status;
535 if (ts->flags & TAPE_FLG_REWIND)
536 tgt->flags |= TGT_REWIND_ON_CLOSE;
537 else
538 tgt->flags &= ~TGT_REWIND_ON_CLOSE;
539
540 if (ts->speed || ts->density) {
541 unsigned int ospeed, odensity;
542 io_req_t ior;
543
544 io_req_alloc(ior,0);
545 ior->io_op = IO_INTERNAL;
546 ior->io_error = 0;
547 ior->io_next = 0;
548 ior->io_count = 0;
549
550 ospeed = tgt->dev_info.tape.speed;
551 odensity = tgt->dev_info.tape.density;
552 tgt->dev_info.tape.speed = ts->speed;
553 tgt->dev_info.tape.density = ts->density;
554
555 ret = sctape_mode_select(tgt, 0, 0, (ospeed == ts->speed), ior);
556 if (ret != SCSI_RET_SUCCESS) {
557 tgt->dev_info.tape.speed = ospeed;
558 tgt->dev_info.tape.density = odensity;
559 }
560
561 io_req_free(ior);
562 }
563
564 break;
565 }
566 /* U*x compat */
567 case MTIOCTOP: {
568 struct tape_params *mt = (struct tape_params *) status;
569 io_req_t ior;
570
571 if (scsi_debug)
572 printf("[sctape_sstatus: %x %x %x]\n",
573 flavor, mt->mt_operation, mt->mt_repeat_count);
574
575 io_req_alloc(ior,0);
576 retry:
577 ior->io_count = 0;
578 ior->io_op = IO_INTERNAL;
579 ior->io_error = 0;
580 ior->io_next = 0;
581 tgt->ior = ior;
582
583 /* compat: in U*x it is a short */
584 switch ((short)(mt->mt_operation)) {
585 case MTWEOF: /* write an end-of-file record */
586 ret = scsi_write_filemarks(tgt, mt->mt_repeat_count, ior);
587 break;
588 case MTFSF: /* forward space file */
589 ret = scsi_space(tgt, SCSI_CMD_SP_FIL, mt->mt_repeat_count, ior);
590 break;
591 case MTBSF: /* backward space file */
592 ret = scsi_space(tgt, SCSI_CMD_SP_FIL, -mt->mt_repeat_count,ior);
593 break;
594 case MTFSR: /* forward space record */
595 ret = scsi_space(tgt, SCSI_CMD_SP_BLOCKS, mt->mt_repeat_count, ior);
596 break;
597 case MTBSR: /* backward space record */
598 ret = scsi_space(tgt, SCSI_CMD_SP_BLOCKS, -mt->mt_repeat_count, ior);
599 break;
600 case MTREW: /* rewind */
601 case MTOFFL: /* rewind and put the drive offline */
602 ret = scsi_rewind(tgt, ior, TRUE);
603 iowait(ior);
604 if ((short)(mt->mt_operation) == MTREW) break;
605 ior->io_op = 0;
606 ior->io_next = 0;
607 ior->io_error = 0;
608 (void) scsi_start_unit(tgt, 0, ior);
609 break;
610 case MTNOP: /* no operation, sets status only */
611 case MTCACHE: /* enable controller cache */
612 case MTNOCACHE: /* disable controller cache */
613 ret = SCSI_RET_SUCCESS;
614 break;
615 default:
616 tgt->ior = 0;
617 io_req_free(ior);
618 return D_INVALID_OPERATION;
619 }
620
621 if (ret == SCSI_RET_RETRY) {
622 timeout(wakeup, ior, 5*hz);
623 await(ior);
624 goto retry;
625 }
626
627 io_req_free(ior);
628 if (ret != SCSI_RET_SUCCESS)
629 return D_IO_ERROR;
630 break;
631 }
632 case MTIOCIEOT:
633 case MTIOCEEOT:
634 default:
635 return D_INVALID_OPERATION;
636 }
637 return D_SUCCESS;
638 }
Cache object: ed0ebbc376b6d96a5a7cb75e2bfe50e8
|