|
|
1.1 root 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 [email protected]
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: * File: rz_tape.c
28: * Author: Alessandro Forin, Carnegie Mellon University
29: * Date: 10/90
30: *
31: * Top layer of the SCSI driver: interface with the MI.
32: * This file contains operations specific to TAPE-like devices.
33: */
34:
35: #include <mach/std_types.h>
36: #include <scsi/compat_30.h>
37:
38: #include <sys/ioctl.h>
39: #ifdef MACH_KERNEL
40: #include <device/tape_status.h>
41: #else /*MACH_KERNEL*/
42: #include <mips/PMAX/tape_status.h>
43: #endif /*MACH_KERNEL*/
44:
45: #include <scsi/scsi.h>
46: #include <scsi/scsi_defs.h>
47: #include <scsi/rz.h>
48:
49: #if (NSCSI > 0)
50:
51:
52: void sctape_start(); /* forward */
53:
54: int scsi_tape_timeout = 5*60; /* secs, tk50 is slow when positioning far apart */
55:
56: int sctape_open(tgt, req)
57: target_info_t *tgt;
58: io_req_t req;
59: {
60: io_return_t ret;
61: io_req_t ior;
62: int i;
63: scsi_mode_sense_data_t *mod;
64:
65: #ifdef MACH_KERNEL
66: req->io_device->flag |= D_EXCL_OPEN;
67: #endif /*MACH_KERNEL*/
68:
69: /* Preferably allow tapes to disconnect */
70: if (BGET(scsi_might_disconnect,(unsigned char)tgt->masterno,tgt->target_id))
71: BSET(scsi_should_disconnect,(unsigned char)tgt->masterno,tgt->target_id);
72:
73: /*
74: * Dummy ior for proper sync purposes
75: */
76: io_req_alloc(ior,0);
77: ior->io_count = 0;
78:
79: /*
80: * Do a mode sense first, some drives might be picky
81: * about changing params [even if the standard might
82: * say otherwise, sigh.]
83: */
84: do {
85: ior->io_op = IO_INTERNAL;
86: ior->io_next = 0;
87: ior->io_error = 0;
88: ret = scsi_mode_sense(tgt, 0, 32, ior);
89: } while (ret == SCSI_RET_RETRY);
90:
91: mod = (scsi_mode_sense_data_t *)tgt->cmd_ptr;
92: if (scsi_debug) {
93: int p[5];
94: bcopy((char*)mod, (char*)p, sizeof(p));
95: printf("[modsns(%x): x%x x%x x%x x%x x%x]", ret,
96: p[0], p[1], p[2], p[3], p[4]);
97: }
98: if (ret == SCSI_RET_DEVICE_DOWN)
99: goto out;
100: if (ret == SCSI_RET_SUCCESS) {
101: tgt->dev_info.tape.read_only = mod->wp;
102: tgt->dev_info.tape.speed = mod->speed;
103: tgt->dev_info.tape.density = mod->bdesc[0].density_code;
104: } /* else they all default sensibly, using zeroes */
105:
106: /* Some tapes have limits on record-length */
107: again:
108: ior->io_op = IO_INTERNAL;
109: ior->io_next = 0;
110: ior->io_error = 0;
111: ret = scsi_read_block_limits( tgt, ior);
112: if (ret == SCSI_RET_RETRY) goto again;
113: if (!ior->io_error && (ret == SCSI_RET_SUCCESS)) {
114: scsi_blimits_data_t *lim;
115: int maxl;
116:
117: lim = (scsi_blimits_data_t *) tgt->cmd_ptr;
118:
119: tgt->block_size = (lim->minlen_msb << 8) |
120: lim->minlen_lsb;
121:
122: maxl = (lim->maxlen_msb << 16) |
123: (lim->maxlen_sb << 8) |
124: lim->maxlen_lsb;
125: if (maxl == 0)
126: maxl = (unsigned)-1;
127: tgt->dev_info.tape.maxreclen = maxl;
128: tgt->dev_info.tape.fixed_size = (maxl == tgt->block_size);
129: } else {
130: /* let the user worry about it */
131: /* default: tgt->block_size = 1; */
132: tgt->dev_info.tape.maxreclen = (unsigned)-1;
133: tgt->dev_info.tape.fixed_size = FALSE;
134: }
135:
136: /* Try hard to do a mode select */
137: for (i = 0; i < 5; i++) {
138: ior->io_op = IO_INTERNAL;
139: ior->io_error = 0;
140: ret = sctape_mode_select(tgt, 0, 0, FALSE, ior);
141: if (ret == SCSI_RET_SUCCESS)
142: break;
143: }
144: if (scsi_watchdog_period < scsi_tape_timeout)
145: scsi_watchdog_period += scsi_tape_timeout;
146:
147: #if 0 /* this might imply rewind, which we do not want, although yes, .. */
148: /* we want the tape loaded */
149: ior->io_op = IO_INTERNAL;
150: ior->io_next = 0;
151: ior->io_error = 0;
152: ret = scsi_start_unit(tgt, SCSI_CMD_SS_START, ior);
153: #endif
154: req->io_device->bsize = tgt->block_size;
155: out:
156: io_req_free(ior);
157: return ret;
158: }
159:
160:
161: io_return_t sctape_close(tgt)
162: target_info_t *tgt;
163: {
164: io_return_t ret = SCSI_RET_SUCCESS;
165: io_req_t ior;
166:
167: /*
168: * Dummy ior for proper sync purposes
169: */
170: io_req_alloc(ior,0);
171: ior->io_op = IO_INTERNAL;
172: ior->io_next = 0;
173: ior->io_count = 0;
174:
175: if (tgt->ior) printf("TAPE: Close with pending requests ?? \n");
176:
177: /* write a filemark if we xtnded/truncated the tape */
178: if (tgt->flags & TGT_WRITTEN_TO) {
179: tgt->ior = ior;
180: ior->io_error = 0;
181: ret = scsi_write_filemarks(tgt, 2, ior);
182: if (ret != SCSI_RET_SUCCESS)
183: printf("%s%d: wfmark failed x%x\n",
184: (*tgt->dev_ops->driver_name)(TRUE), tgt->target_id, ret);
185: /*
186: * Don't bother repositioning if we'll rewind it
187: */
188: if (tgt->flags & TGT_REWIND_ON_CLOSE)
189: goto rew;
190: retry:
191: tgt->ior = ior;
192: ior->io_op = IO_INTERNAL;
193: ior->io_error = 0;
194: ior->io_next = 0;
195: ret = scsi_space(tgt, SCSI_CMD_SP_FIL, -1, ior);
196: if (ret != SCSI_RET_SUCCESS) {
197: if (ret == SCSI_RET_RETRY) {
198: timeout(wakeup, tgt, hz);
199: await(tgt);
200: goto retry;
201: }
202: printf("%s%d: bspfile failed x%x\n",
203: (*tgt->dev_ops->driver_name)(TRUE), tgt->target_id, ret);
204: }
205: }
206: rew:
207: if (tgt->flags & TGT_REWIND_ON_CLOSE) {
208: /* Rewind tape */
209: ior->io_error = 0;
210: ior->io_op = IO_INTERNAL;
211: ior->io_error = 0;
212: tgt->ior = ior;
213: (void) scsi_rewind(tgt, ior, FALSE);
214: iowait(ior);
215: if (tgt->done == SCSI_RET_RETRY) {
216: timeout(wakeup, tgt, 5*hz);
217: await(tgt);
218: goto rew;
219: }
220: }
221: io_req_free(ior);
222:
223: tgt->flags &= ~(TGT_ONLINE|TGT_WRITTEN_TO|TGT_REWIND_ON_CLOSE);
224: return ret;
225: }
226:
227: int sctape_strategy(ior)
228: register io_req_t ior;
229: {
230: target_info_t *tgt;
231: register int i = ior->io_unit;
232:
233: tgt = scsi_softc[rzcontroller(i)]->target[rzslave(i)];
234:
235: if (((ior->io_op & IO_READ) == 0) &&
236: tgt->dev_info.tape.read_only) {
237: ior->io_error = D_INVALID_OPERATION;
238: ior->io_op |= IO_ERROR;
239: ior->io_residual = ior->io_count;
240: iodone(ior);
241: return ior->io_error;
242: }
243:
244: return rz_simpleq_strategy( ior, sctape_start);
245: }
246:
247: static void
248: do_residue(ior, sns, bsize)
249: io_req_t ior;
250: scsi_sense_data_t *sns;
251: int bsize;
252: {
253: int residue;
254:
255: /* Not an error situation */
256: ior->io_error = 0;
257: ior->io_op &= ~IO_ERROR;
258:
259: if (!sns->addr_valid) {
260: ior->io_residual = ior->io_count;
261: return;
262: }
263:
264: residue = sns->u.xtended.info0 << 24 |
265: sns->u.xtended.info1 << 16 |
266: sns->u.xtended.info2 << 8 |
267: sns->u.xtended.info3;
268: /* fixed ? */
269: residue *= bsize;
270: /*
271: * NOTE: residue == requested - actual
272: * We only care if > 0
273: */
274: if (residue < 0) residue = 0;/* sanity */
275: ior->io_residual += residue;
276: }
277:
278: void sctape_start( tgt, done)
279: target_info_t *tgt;
280: boolean_t done;
281: {
282: io_req_t head, ior = tgt->ior;
283:
284: if (ior == 0)
285: return;
286:
287: if (done) {
288:
289: /* see if we must retry */
290: if ((tgt->done == SCSI_RET_RETRY) &&
291: ((ior->io_op & IO_INTERNAL) == 0)) {
292: delay(1000000);/*XXX*/
293: goto start;
294: } else
295: /* got a bus reset ? ouch, that hurts */
296: if (tgt->done == (SCSI_RET_ABORTED|SCSI_RET_RETRY)) {
297: /*
298: * we really cannot retry because the tape position
299: * is lost.
300: */
301: printf("Lost tape position\n");
302: ior->io_error = D_IO_ERROR;
303: ior->io_op |= IO_ERROR;
304: } else
305:
306: /* check completion status */
307:
308: if (tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) {
309: scsi_sense_data_t *sns;
310:
311: ior->io_op = ior->io_temporary;
312: ior->io_error = D_IO_ERROR;
313: ior->io_op |= IO_ERROR;
314:
315: sns = (scsi_sense_data_t *)tgt->cmd_ptr;
316:
317: if (scsi_debug)
318: scsi_print_sense_data(sns);
319:
320: if (scsi_check_sense_data(tgt, sns)) {
321: if (sns->u.xtended.ili) {
322: if (ior->io_op & IO_READ) {
323: do_residue(ior, sns, tgt->block_size);
324: if (scsi_debug)
325: printf("Tape Short Read (%d)\n",
326: ior->io_residual);
327: }
328: } else if (sns->u.xtended.eom) {
329: do_residue(ior, sns, tgt->block_size);
330: if (scsi_debug)
331: printf("End of Physical Tape!\n");
332: } else if (sns->u.xtended.fm) {
333: do_residue(ior, sns, tgt->block_size);
334: if (scsi_debug)
335: printf("File Mark\n");
336: }
337: }
338: }
339:
340: else if (tgt->done != SCSI_RET_SUCCESS) {
341:
342: if (tgt->done == SCSI_RET_NEED_SENSE) {
343:
344: ior->io_temporary = ior->io_op;
345: ior->io_op = IO_INTERNAL;
346: if (scsi_debug)
347: printf("[NeedSns x%x x%x]", ior->io_residual, ior->io_count);
348: scsi_request_sense(tgt, ior, 0);
349: return;
350:
351: } else if (tgt->done == SCSI_RET_RETRY) {
352: /* only retry here READs and WRITEs */
353: if ((ior->io_op & IO_INTERNAL) == 0) {
354: ior->io_residual = 0;
355: goto start;
356: } else{
357: ior->io_error = D_WOULD_BLOCK;
358: ior->io_op |= IO_ERROR;
359: }
360: } else {
361: ior->io_error = D_IO_ERROR;
362: ior->io_op |= IO_ERROR;
363: }
364: }
365:
366: if (scsi_debug)
367: printf("[Resid x%x]", ior->io_residual);
368:
369: /* dequeue next one */
370: head = ior;
371:
372: simple_lock(&tgt->target_lock);
373: ior = head->io_next;
374: tgt->ior = ior;
375: if (ior)
376: ior->io_prev = head->io_prev;
377: simple_unlock(&tgt->target_lock);
378:
379: iodone(head);
380:
381: if (ior == 0)
382: return;
383: }
384: ior->io_residual = 0;
385: start:
386: if (ior->io_op & IO_READ) {
387: tgt->flags &= ~TGT_WRITTEN_TO;
388: sctape_read( tgt, ior );
389: } else if ((ior->io_op & IO_INTERNAL) == 0) {
390: tgt->flags |= TGT_WRITTEN_TO;
391: sctape_write( tgt, ior );
392: }
393: }
394:
395: io_return_t
396: sctape_get_status( dev, tgt, flavor, status, status_count)
397: int dev;
398: target_info_t *tgt;
399: dev_flavor_t flavor;
400: dev_status_t status;
401: natural_t *status_count;
402: {
403: switch (flavor) {
404: case DEV_GET_SIZE:
405:
406: status[DEV_GET_SIZE_DEVICE_SIZE] = 0;
407: status[DEV_GET_SIZE_RECORD_SIZE] = tgt->block_size;
408: *status_count = DEV_GET_SIZE_COUNT;
409: break;
410: case TAPE_STATUS: {
411: struct tape_status *ts = (struct tape_status *) status;
412:
413: ts->mt_type = MT_ISSCSI;
414: ts->speed = tgt->dev_info.tape.speed;
415: ts->density = tgt->dev_info.tape.density;
416: ts->flags = (tgt->flags & TGT_REWIND_ON_CLOSE) ?
417: TAPE_FLG_REWIND : 0;
418: if (tgt->dev_info.tape.read_only)
419: ts->flags |= TAPE_FLG_WP;
420: #ifdef MACH_KERNEL
421: *status_count = TAPE_STATUS_COUNT;
422: #endif
423:
424: break;
425: }
426: /* U*x compat */
427: case MTIOCGET: {
428: struct mtget *g = (struct mtget *) status;
429:
430: bzero(g, sizeof(struct mtget));
431: g->mt_type = 0x7; /* Ultrix compat */
432: #ifdef MACH_KERNEL
433: *status_count = sizeof(struct mtget)/sizeof(int);
434: #endif
435: break;
436: }
437: default:
438: return D_INVALID_OPERATION;
439: }
440: return D_SUCCESS;
441: }
442:
443: io_return_t
444: sctape_set_status( dev, tgt, flavor, status, status_count)
445: int dev;
446: target_info_t *tgt;
447: dev_flavor_t flavor;
448: dev_status_t status;
449: natural_t status_count;
450: {
451: scsi_ret_t ret;
452:
453: switch (flavor) {
454: case TAPE_STATUS: {
455: struct tape_status *ts = (struct tape_status *) status;
456: if (ts->flags & TAPE_FLG_REWIND)
457: tgt->flags |= TGT_REWIND_ON_CLOSE;
458: else
459: tgt->flags &= ~TGT_REWIND_ON_CLOSE;
460:
461: if (ts->speed || ts->density) {
462: unsigned int ospeed, odensity;
463: io_req_t ior;
464:
465: io_req_alloc(ior,0);
466: ior->io_op = IO_INTERNAL;
467: ior->io_error = 0;
468: ior->io_next = 0;
469: ior->io_count = 0;
470:
471: ospeed = tgt->dev_info.tape.speed;
472: odensity = tgt->dev_info.tape.density;
473: tgt->dev_info.tape.speed = ts->speed;
474: tgt->dev_info.tape.density = ts->density;
475:
476: ret = sctape_mode_select(tgt, 0, 0, (ospeed == ts->speed), ior);
477: if (ret != SCSI_RET_SUCCESS) {
478: tgt->dev_info.tape.speed = ospeed;
479: tgt->dev_info.tape.density = odensity;
480: }
481:
482: io_req_free(ior);
483: }
484:
485: break;
486: }
487: /* U*x compat */
488: case MTIOCTOP: {
489: struct tape_params *mt = (struct tape_params *) status;
490: io_req_t ior;
491:
492: if (scsi_debug)
493: printf("[sctape_sstatus: %x %x %x]\n",
494: flavor, mt->mt_operation, mt->mt_repeat_count);
495:
496: io_req_alloc(ior,0);
497: retry:
498: ior->io_count = 0;
499: ior->io_op = IO_INTERNAL;
500: ior->io_error = 0;
501: ior->io_next = 0;
502: tgt->ior = ior;
503:
504: /* compat: in U*x it is a short */
505: switch ((short)(mt->mt_operation)) {
506: case MTWEOF: /* write an end-of-file record */
507: ret = scsi_write_filemarks(tgt, mt->mt_repeat_count, ior);
508: break;
509: case MTFSF: /* forward space file */
510: ret = scsi_space(tgt, SCSI_CMD_SP_FIL, mt->mt_repeat_count, ior);
511: break;
512: case MTBSF: /* backward space file */
513: ret = scsi_space(tgt, SCSI_CMD_SP_FIL, -mt->mt_repeat_count,ior);
514: break;
515: case MTFSR: /* forward space record */
516: ret = scsi_space(tgt, SCSI_CMD_SP_BLOCKS, mt->mt_repeat_count, ior);
517: break;
518: case MTBSR: /* backward space record */
519: ret = scsi_space(tgt, SCSI_CMD_SP_BLOCKS, -mt->mt_repeat_count, ior);
520: break;
521: case MTREW: /* rewind */
522: case MTOFFL: /* rewind and put the drive offline */
523: ret = scsi_rewind(tgt, ior, TRUE);
524: iowait(ior);
525: if ((short)(mt->mt_operation) == MTREW) break;
526: ior->io_op = 0;
527: ior->io_next = 0;
528: ior->io_error = 0;
529: (void) scsi_start_unit(tgt, 0, ior);
530: break;
531: case MTNOP: /* no operation, sets status only */
532: case MTCACHE: /* enable controller cache */
533: case MTNOCACHE: /* disable controller cache */
534: ret = SCSI_RET_SUCCESS;
535: break;
536: default:
537: tgt->ior = 0;
538: io_req_free(ior);
539: return D_INVALID_OPERATION;
540: }
541:
542: if (ret == SCSI_RET_RETRY) {
543: timeout(wakeup, ior, 5*hz);
544: await(ior);
545: goto retry;
546: }
547:
548: io_req_free(ior);
549: if (ret != SCSI_RET_SUCCESS)
550: return D_IO_ERROR;
551: break;
552: }
553: case MTIOCIEOT:
554: case MTIOCEEOT:
555: default:
556: return D_INVALID_OPERATION;
557: }
558: return D_SUCCESS;
559: }
560: #endif /* NSCSI > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.