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