mscp_tape.c revision 1.13 1 /* $NetBSD: mscp_tape.c,v 1.13 1999/05/29 19:12:42 ragge Exp $ */
2 /*
3 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed at Ludd, University of
17 * Lule}, Sweden and its contributors.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33
34 /*
35 * MSCP tape device driver
36 */
37
38 /*
39 * TODO
40 * Write status handling code.
41 */
42
43 #include <sys/param.h>
44 #include <sys/device.h>
45 #include <sys/kernel.h>
46 #include <sys/buf.h>
47 #include <sys/ioccom.h>
48 #include <sys/mtio.h>
49 #include <sys/fcntl.h>
50 #include <sys/malloc.h>
51 #include <sys/systm.h>
52 #include <sys/proc.h>
53
54 #include <machine/cpu.h>
55
56 #include <vax/mscp/mscp.h>
57 #include <vax/mscp/mscpvar.h>
58
59 #include "locators.h"
60
61 /*
62 * Drive status, per drive
63 */
64 struct mt_softc {
65 struct device mt_dev; /* Autoconf struct */
66 int mt_state; /* open/closed state */
67 int mt_hwunit; /* Hardware unit number */
68 int mt_inuse; /* Locks the tape drive for others */
69 int mt_waswrite; /* Last operation was a write op */
70 int mt_serex; /* Got serious exception */
71 int mt_ioctlerr; /* Error after last ioctl */
72 };
73
74 #define MT_OFFLINE 0
75 #define MT_ONLINE 1
76
77 int mtmatch __P((struct device *, struct cfdata *, void *));
78 void mtattach __P((struct device *, struct device *, void *));
79 void mtdgram __P((struct device *, struct mscp *, struct mscp_softc *));
80 void mtiodone __P((struct device *, struct buf *));
81 int mtonline __P((struct device *, struct mscp *));
82 int mtgotstatus __P((struct device *, struct mscp *));
83 int mtioerror __P((struct device *, struct mscp *, struct buf *));
84 void mtfillin __P((struct buf *, struct mscp *));
85 int mtopen __P((dev_t, int, int, struct proc *));
86 int mtclose __P((dev_t, int, int, struct proc *));
87 void mtstrategy __P((struct buf *));
88 int mtread __P((dev_t, struct uio *));
89 int mtwrite __P((dev_t, struct uio *));
90 int mtioctl __P((dev_t, int, caddr_t, int, struct proc *));
91 int mtdump __P((dev_t, daddr_t, caddr_t, size_t));
92 int mtcmd __P((struct mt_softc *, int, int, int));
93 void mtcmddone __P((struct device *, struct mscp *));
94 int mt_putonline __P((struct mt_softc *));
95
96 struct mscp_device mt_device = {
97 mtdgram,
98 mtiodone,
99 mtonline,
100 mtgotstatus,
101 0,
102 mtioerror,
103 0,
104 mtfillin,
105 mtcmddone,
106 };
107
108 /* This is not good, should allow more than 4 tapes/device type */
109 #define mtunit(dev) (minor(dev) & T_UNIT)
110 #define mtnorewind(dev) (dev & T_NOREWIND)
111 #define mthdensity(dev) (dev & T_1600BPI)
112
113 struct cfattach mt_ca = {
114 sizeof(struct mt_softc), mtmatch, mtattach
115 };
116
117 extern struct cfdriver mt_cd;
118
119 /*
120 * More driver definitions, for generic MSCP code.
121 */
122
123 int
124 mtmatch(parent, cf, aux)
125 struct device *parent;
126 struct cfdata *cf;
127 void *aux;
128 {
129 struct drive_attach_args *da = aux;
130 struct mscp *mp = da->da_mp;
131
132 if ((da->da_typ & MSCPBUS_TAPE) == 0)
133 return 0;
134 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
135 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
136 return 0;
137 return 1;
138 }
139
140 /*
141 * The attach routine only checks and prints drive type.
142 */
143 void
144 mtattach(parent, self, aux)
145 struct device *parent, *self;
146 void *aux;
147 {
148 struct mt_softc *mt = (void *)self;
149 struct drive_attach_args *da = aux;
150 struct mscp *mp = da->da_mp;
151 struct mscp_softc *mi = (void *)parent;
152
153 mt->mt_hwunit = mp->mscp_unit;
154 mi->mi_dp[mp->mscp_unit] = self;
155
156 disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
157 }
158
159 /*
160 * (Try to) put the drive online. This is done the first time the
161 * drive is opened, or if it has fallen offline.
162 */
163 int
164 mt_putonline(mt)
165 struct mt_softc *mt;
166 {
167 struct mscp *mp;
168 struct mscp_softc *mi = (struct mscp_softc *)mt->mt_dev.dv_parent;
169 volatile int i;
170
171 (volatile int)mt->mt_state = MT_OFFLINE;
172 mp = mscp_getcp(mi, MSCP_WAIT);
173 mp->mscp_opcode = M_OP_ONLINE;
174 mp->mscp_unit = mt->mt_hwunit;
175 mp->mscp_cmdref = (long)&mt->mt_state;
176 *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
177
178 /* Poll away */
179 i = *mi->mi_ip;
180 if (tsleep(&mt->mt_state, PRIBIO, "mtonline", 240 * hz))
181 return MSCP_FAILED;
182
183 if ((volatile int)mt->mt_state != MT_ONLINE)
184 return MSCP_FAILED;
185
186 return MSCP_DONE;
187 }
188 /*
189 * Open a drive.
190 */
191 /*ARGSUSED*/
192 int
193 mtopen(dev, flag, fmt, p)
194 dev_t dev;
195 int flag, fmt;
196 struct proc *p;
197 {
198 register struct mt_softc *mt;
199 int unit;
200
201 /*
202 * Make sure this is a reasonable open request.
203 */
204 unit = mtunit(dev);
205 if (unit >= mt_cd.cd_ndevs)
206 return ENXIO;
207 mt = mt_cd.cd_devs[unit];
208 if (mt == 0)
209 return ENXIO;
210
211 if (mt->mt_inuse)
212 return EBUSY;
213 mt->mt_inuse = 1;
214
215 if (mt_putonline(mt) == MSCP_FAILED) {
216 mt->mt_inuse = 0;
217 return EIO;
218 }
219
220 return 0;
221 }
222
223 /* ARGSUSED */
224 int
225 mtclose(dev, flags, fmt, p)
226 dev_t dev;
227 int flags, fmt;
228 struct proc *p;
229 {
230 int unit = mtunit(dev);
231 struct mt_softc *mt = mt_cd.cd_devs[unit];
232
233 /*
234 * If we just have finished a writing, write EOT marks.
235 */
236 if ((flags & FWRITE) && mt->mt_waswrite) {
237 mtcmd(mt, MTWEOF, 0, 0);
238 mtcmd(mt, MTWEOF, 0, 0);
239 mtcmd(mt, MTBSR, 1, 0);
240 }
241 if (mtnorewind(dev) == 0)
242 mtcmd(mt, MTREW, 0, 1);
243 if (mt->mt_serex)
244 mtcmd(mt, -1, 0, 0);
245
246 mt->mt_inuse = 0; /* Release the tape */
247 return 0;
248 }
249
250 void
251 mtstrategy(bp)
252 register struct buf *bp;
253 {
254 register int unit;
255 register struct mt_softc *mt;
256
257 /*
258 * Make sure this is a reasonable drive to use.
259 */
260 unit = mtunit(bp->b_dev);
261 if (unit > mt_cd.cd_ndevs || (mt = mt_cd.cd_devs[unit]) == NULL) {
262 bp->b_error = ENXIO;
263 goto bad;
264 }
265
266 mt->mt_waswrite = bp->b_flags & B_READ ? 0 : 1;
267 mscp_strategy(bp, mt->mt_dev.dv_parent);
268 return;
269
270 bad:
271 bp->b_flags |= B_ERROR;
272 biodone(bp);
273 }
274
275 int
276 mtread(dev, uio)
277 dev_t dev;
278 struct uio *uio;
279 {
280
281 return (physio(mtstrategy, NULL, dev, B_READ, minphys, uio));
282 }
283
284 int
285 mtwrite(dev, uio)
286 dev_t dev;
287 struct uio *uio;
288 {
289
290 return (physio(mtstrategy, NULL, dev, B_WRITE, minphys, uio));
291 }
292
293 void
294 mtiodone(usc, bp)
295 struct device *usc;
296 struct buf *bp;
297 {
298
299 biodone(bp);
300 }
301
302 /*
303 * Fill in drive addresses in a mscp packet waiting for transfer.
304 */
305 void
306 mtfillin(bp, mp)
307 struct buf *bp;
308 struct mscp *mp;
309 {
310 int unit = mtunit(bp->b_dev);
311 struct mt_softc *mt = mt_cd.cd_devs[unit];
312
313 mp->mscp_unit = mt->mt_hwunit;
314 if (mt->mt_serex == 2) {
315 mp->mscp_modifier = M_MD_CLSEX;
316 mt->mt_serex = 0;
317 } else
318 mp->mscp_modifier = 0;
319
320 mp->mscp_seq.seq_bytecount = bp->b_bcount;
321 }
322
323 /*
324 * Handle an error datagram.
325 */
326 void
327 mtdgram(usc, mp, mi)
328 struct device *usc;
329 struct mscp *mp;
330 struct mscp_softc *mi;
331 {
332 if (mscp_decodeerror(usc == NULL?"unconf mt" : usc->dv_xname, mp, mi))
333 return;
334 }
335
336 /*
337 * A drive came on line, make sure it really _is_ on line before
338 * trying to use it.
339 */
340 int
341 mtonline(usc, mp)
342 struct device *usc;
343 struct mscp *mp;
344 {
345 register struct mt_softc *mt = (void *)usc;
346
347 wakeup((caddr_t)&mt->mt_state);
348 if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS)
349 mt->mt_state = MT_ONLINE;
350
351 return (MSCP_DONE);
352 }
353
354 /*
355 * We got some (configured) unit's status. Return DONE.
356 */
357 int
358 mtgotstatus(usc, mp)
359 register struct device *usc;
360 register struct mscp *mp;
361 {
362 return (MSCP_DONE);
363 }
364
365 static char *mt_ioerrs[] = {
366 "invalid command", /* 1 M_ST_INVALCMD */
367 "command aborted", /* 2 M_ST_ABORTED */
368 "unit offline", /* 3 M_ST_OFFLINE */
369 "unknown", /* 4 M_ST_AVAILABLE */
370 "unknown", /* 5 M_ST_MFMTERR */
371 "unit write protected", /* 6 M_ST_WRPROT */
372 "compare error", /* 7 M_ST_COMPERR */
373 "data error", /* 8 M_ST_DATAERR */
374 "host buffer access error", /* 9 M_ST_HOSTBUFERR */
375 "controller error", /* 10 M_ST_CTLRERR */
376 "drive error", /* 11 M_ST_DRIVEERR */
377 "formatter error", /* 12 M_ST_FORMATTERR */
378 "BOT encountered", /* 13 M_ST_BOT */
379 "tape mark encountered",/* 14 M_ST_TAPEMARK */
380 "unknown", /* 15 */
381 "record data truncated",/* 16 M_ST_RDTRUNC */
382 };
383
384 /*
385 * An I/O error, may be because of a tapemark encountered.
386 * Check that before failing.
387 */
388 /*ARGSUSED*/
389 int
390 mtioerror(usc, mp, bp)
391 register struct device *usc;
392 register struct mscp *mp;
393 struct buf *bp;
394 {
395 struct mt_softc *mt = (void *)usc;
396 int st = mp->mscp_status & M_ST_MASK;
397
398 if (mp->mscp_flags & M_EF_SEREX)
399 mt->mt_serex = 1;
400 if (st == M_ST_TAPEMARK)
401 mt->mt_serex = 2;
402 else {
403 if (st && st < 17)
404 printf("%s: error %d (%s)\n", mt->mt_dev.dv_xname, st,
405 mt_ioerrs[st-1]);
406 else
407 printf("%s: error %d\n", mt->mt_dev.dv_xname, st);
408 bp->b_flags |= B_ERROR;
409 bp->b_error = EROFS;
410 }
411
412 return (MSCP_DONE);
413 }
414
415 /*
416 * I/O controls.
417 */
418 int
419 mtioctl(dev, cmd, data, flag, p)
420 dev_t dev;
421 int cmd;
422 caddr_t data;
423 int flag;
424 struct proc *p;
425 {
426 register int unit = mtunit(dev);
427 register struct mt_softc *mt = mt_cd.cd_devs[unit];
428 struct mtop *mtop;
429 struct mtget *mtget;
430 int error = 0, count;
431
432 count = mtop->mt_count;
433
434 switch (cmd) {
435
436 case MTIOCTOP:
437 mtop = (void *)data;
438 if (mtop->mt_op == MTWEOF) {
439 while (mtop->mt_count-- > 0)
440 if ((error = mtcmd(mt, mtop->mt_op, 0, 0)))
441 break;
442 } else
443 error = mtcmd(mt, mtop->mt_op, mtop->mt_count, 0);
444
445 case MTIOCGET:
446 mtget = (void *)data;
447 mtget->mt_type = MT_ISTMSCP;
448 /* XXX we need to fill in more fields here */
449 break;
450
451 default:
452 error = ENXIO;
453 break;
454 }
455 return (error);
456 }
457
458 /*
459 * No crash dump support...
460 */
461 int
462 mtdump(dev, blkno, va, size)
463 dev_t dev;
464 daddr_t blkno;
465 caddr_t va;
466 size_t size;
467 {
468 return -1;
469 }
470
471 /*
472 * Send a command to the tape drive. Wait until the command is
473 * finished before returning.
474 * This routine must only be called when there are no data transfer
475 * active on this device. Can we be sure of this? Or does the ctlr
476 * queue up all command packets and take them in sequential order?
477 * It sure would be nice if my manual stated this... /ragge
478 */
479 int
480 mtcmd(mt, cmd, count, complete)
481 struct mt_softc *mt;
482 int cmd, count, complete;
483 {
484 struct mscp *mp;
485 struct mscp_softc *mi = (void *)mt->mt_dev.dv_parent;
486 volatile int i;
487
488 mp = mscp_getcp(mi, MSCP_WAIT);
489
490 mt->mt_ioctlerr = 0;
491 mp->mscp_unit = mt->mt_hwunit;
492 mp->mscp_cmdref = -1;
493 *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
494
495 switch (cmd) {
496 case MTWEOF:
497 mp->mscp_opcode = M_OP_WRITM;
498 break;
499
500 case MTBSF:
501 mp->mscp_modifier = M_MD_REVERSE;
502 case MTFSF:
503 mp->mscp_opcode = M_OP_POS;
504 mp->mscp_seq.seq_buffer = count;
505 break;
506
507 case MTBSR:
508 mp->mscp_modifier = M_MD_REVERSE;
509 case MTFSR:
510 mp->mscp_opcode = M_OP_POS;
511 mp->mscp_modifier |= M_MD_OBJCOUNT;
512 mp->mscp_seq.seq_bytecount = count;
513 break;
514
515 case MTREW:
516 mp->mscp_opcode = M_OP_POS;
517 mp->mscp_modifier = M_MD_REWIND | M_MD_CLSEX;
518 if (complete)
519 mp->mscp_modifier |= M_MD_IMMEDIATE;
520 mt->mt_serex = 0;
521 break;
522
523 case MTOFFL:
524 mp->mscp_opcode = M_OP_AVAILABLE;
525 mp->mscp_modifier = M_MD_UNLOAD | M_MD_CLSEX;
526 mt->mt_serex = 0;
527 break;
528
529 case MTNOP:
530 mp->mscp_opcode = M_OP_GETUNITST;
531 break;
532
533 case -1: /* Clear serious exception only */
534 mp->mscp_opcode = M_OP_POS;
535 mp->mscp_modifier = M_MD_CLSEX;
536 mt->mt_serex = 0;
537 break;
538
539 default:
540 printf("Bad ioctl %x\n", cmd);
541 mp->mscp_opcode = M_OP_POS;
542 break;
543 }
544
545 i = *mi->mi_ip;
546 tsleep(&mt->mt_inuse, PRIBIO, "mtioctl", 0);
547 return mt->mt_ioctlerr;
548 }
549
550 /*
551 * Called from bus routines whenever a non-data transfer is finished.
552 */
553 void
554 mtcmddone(usc, mp)
555 struct device *usc;
556 struct mscp *mp;
557 {
558 struct mt_softc *mt = (void *)usc;
559
560 if (mp->mscp_status) {
561 mt->mt_ioctlerr = EIO;
562 printf("%s: bad status %x\n", mt->mt_dev.dv_xname,
563 mp->mscp_status);
564 }
565 wakeup(&mt->mt_inuse);
566 }
567