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