mscp_tape.c revision 1.16 1 /* $NetBSD: mscp_tape.c,v 1.16 2001/11/13 07:38:28 lukem 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/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: mscp_tape.c,v 1.16 2001/11/13 07:38:28 lukem Exp $");
45
46 #include <sys/param.h>
47 #include <sys/device.h>
48 #include <sys/kernel.h>
49 #include <sys/buf.h>
50 #include <sys/ioccom.h>
51 #include <sys/mtio.h>
52 #include <sys/fcntl.h>
53 #include <sys/malloc.h>
54 #include <sys/systm.h>
55 #include <sys/proc.h>
56
57 #include <machine/bus.h>
58 #include <machine/cpu.h>
59
60 #include <dev/mscp/mscp.h>
61 #include <dev/mscp/mscpreg.h>
62 #include <dev/mscp/mscpvar.h>
63
64 #include "locators.h"
65
66 /*
67 * Drive status, per drive
68 */
69 struct mt_softc {
70 struct device mt_dev; /* Autoconf struct */
71 int mt_state; /* open/closed state */
72 int mt_hwunit; /* Hardware unit number */
73 int mt_inuse; /* Locks the tape drive for others */
74 int mt_waswrite; /* Last operation was a write op */
75 int mt_serex; /* Got serious exception */
76 int mt_ioctlerr; /* Error after last ioctl */
77 };
78
79 #define MT_OFFLINE 0
80 #define MT_ONLINE 1
81
82 int mtmatch __P((struct device *, struct cfdata *, void *));
83 void mtattach __P((struct device *, struct device *, void *));
84 void mtdgram __P((struct device *, struct mscp *, struct mscp_softc *));
85 void mtiodone __P((struct device *, struct buf *));
86 int mtonline __P((struct device *, struct mscp *));
87 int mtgotstatus __P((struct device *, struct mscp *));
88 int mtioerror __P((struct device *, struct mscp *, struct buf *));
89 void mtfillin __P((struct buf *, struct mscp *));
90 int mtopen __P((dev_t, int, int, struct proc *));
91 int mtclose __P((dev_t, int, int, struct proc *));
92 void mtstrategy __P((struct buf *));
93 int mtread __P((dev_t, struct uio *));
94 int mtwrite __P((dev_t, struct uio *));
95 int mtioctl __P((dev_t, int, caddr_t, int, struct proc *));
96 int mtdump __P((dev_t, daddr_t, caddr_t, size_t));
97 int mtcmd __P((struct mt_softc *, int, int, int));
98 void mtcmddone __P((struct device *, struct mscp *));
99 int mt_putonline __P((struct mt_softc *));
100
101 struct mscp_device mt_device = {
102 mtdgram,
103 mtiodone,
104 mtonline,
105 mtgotstatus,
106 0,
107 mtioerror,
108 0,
109 mtfillin,
110 mtcmddone,
111 };
112
113 /* This is not good, should allow more than 4 tapes/device type */
114 #define mtunit(dev) (minor(dev) & T_UNIT)
115 #define mtnorewind(dev) (dev & T_NOREWIND)
116 #define mthdensity(dev) (dev & T_1600BPI)
117
118 struct cfattach mt_ca = {
119 sizeof(struct mt_softc), mtmatch, mtattach
120 };
121
122 extern struct cfdriver mt_cd;
123
124 /*
125 * More driver definitions, for generic MSCP code.
126 */
127
128 int
129 mtmatch(parent, cf, aux)
130 struct device *parent;
131 struct cfdata *cf;
132 void *aux;
133 {
134 struct drive_attach_args *da = aux;
135 struct mscp *mp = da->da_mp;
136
137 if ((da->da_typ & MSCPBUS_TAPE) == 0)
138 return 0;
139 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
140 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
141 return 0;
142 return 1;
143 }
144
145 /*
146 * The attach routine only checks and prints drive type.
147 */
148 void
149 mtattach(parent, self, aux)
150 struct device *parent, *self;
151 void *aux;
152 {
153 struct mt_softc *mt = (void *)self;
154 struct drive_attach_args *da = aux;
155 struct mscp *mp = da->da_mp;
156 struct mscp_softc *mi = (void *)parent;
157
158 mt->mt_hwunit = mp->mscp_unit;
159 mi->mi_dp[mp->mscp_unit] = self;
160
161 disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
162 }
163
164 /*
165 * (Try to) put the drive online. This is done the first time the
166 * drive is opened, or if it has fallen offline.
167 */
168 int
169 mt_putonline(mt)
170 struct mt_softc *mt;
171 {
172 struct mscp *mp;
173 struct mscp_softc *mi = (struct mscp_softc *)mt->mt_dev.dv_parent;
174 volatile int i;
175
176 (volatile int)mt->mt_state = MT_OFFLINE;
177 mp = mscp_getcp(mi, MSCP_WAIT);
178 mp->mscp_opcode = M_OP_ONLINE;
179 mp->mscp_unit = mt->mt_hwunit;
180 mp->mscp_cmdref = (long)&mt->mt_state;
181 *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
182
183 /* Poll away */
184 i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
185 if (tsleep(&mt->mt_state, PRIBIO, "mtonline", 240 * hz))
186 return MSCP_FAILED;
187
188 if ((volatile int)mt->mt_state != MT_ONLINE)
189 return MSCP_FAILED;
190
191 return MSCP_DONE;
192 }
193 /*
194 * Open a drive.
195 */
196 /*ARGSUSED*/
197 int
198 mtopen(dev, flag, fmt, p)
199 dev_t dev;
200 int flag, fmt;
201 struct proc *p;
202 {
203 struct mt_softc *mt;
204 int unit;
205
206 /*
207 * Make sure this is a reasonable open request.
208 */
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 if (mt_putonline(mt) == MSCP_FAILED) {
221 mt->mt_inuse = 0;
222 return EIO;
223 }
224
225 return 0;
226 }
227
228 /* ARGSUSED */
229 int
230 mtclose(dev, flags, fmt, p)
231 dev_t dev;
232 int flags, fmt;
233 struct proc *p;
234 {
235 int unit = mtunit(dev);
236 struct mt_softc *mt = mt_cd.cd_devs[unit];
237
238 /*
239 * If we just have finished a writing, write EOT marks.
240 */
241 if ((flags & FWRITE) && mt->mt_waswrite) {
242 mtcmd(mt, MTWEOF, 0, 0);
243 mtcmd(mt, MTWEOF, 0, 0);
244 mtcmd(mt, MTBSR, 1, 0);
245 }
246 if (mtnorewind(dev) == 0)
247 mtcmd(mt, MTREW, 0, 1);
248 if (mt->mt_serex)
249 mtcmd(mt, -1, 0, 0);
250
251 mt->mt_inuse = 0; /* Release the tape */
252 return 0;
253 }
254
255 void
256 mtstrategy(bp)
257 struct buf *bp;
258 {
259 int unit;
260 struct mt_softc *mt;
261
262 /*
263 * Make sure this is a reasonable drive to use.
264 */
265 unit = mtunit(bp->b_dev);
266 if (unit > mt_cd.cd_ndevs || (mt = mt_cd.cd_devs[unit]) == 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(dev, uio)
282 dev_t dev;
283 struct uio *uio;
284 {
285
286 return (physio(mtstrategy, NULL, dev, B_READ, minphys, uio));
287 }
288
289 int
290 mtwrite(dev, uio)
291 dev_t dev;
292 struct uio *uio;
293 {
294
295 return (physio(mtstrategy, NULL, dev, 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(bp->b_dev);
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(dev, cmd, data, flag, p)
425 dev_t dev;
426 int cmd;
427 caddr_t data;
428 int flag;
429 struct proc *p;
430 {
431 int unit = mtunit(dev);
432 struct mt_softc *mt = mt_cd.cd_devs[unit];
433 struct mtop *mtop;
434 struct mtget *mtget;
435 int error = 0, count;
436
437 count = mtop->mt_count;
438
439 switch (cmd) {
440
441 case MTIOCTOP:
442 mtop = (void *)data;
443 if (mtop->mt_op == MTWEOF) {
444 while (mtop->mt_count-- > 0)
445 if ((error = mtcmd(mt, mtop->mt_op, 0, 0)))
446 break;
447 } else
448 error = mtcmd(mt, mtop->mt_op, mtop->mt_count, 0);
449
450 case MTIOCGET:
451 mtget = (void *)data;
452 mtget->mt_type = MT_ISTMSCP;
453 /* XXX we need to fill in more fields here */
454 break;
455
456 default:
457 error = ENXIO;
458 break;
459 }
460 return (error);
461 }
462
463 /*
464 * No crash dump support...
465 */
466 int
467 mtdump(dev, blkno, va, size)
468 dev_t dev;
469 daddr_t blkno;
470 caddr_t va;
471 size_t size;
472 {
473 return -1;
474 }
475
476 /*
477 * Send a command to the tape drive. Wait until the command is
478 * finished before returning.
479 * This routine must only be called when there are no data transfer
480 * active on this device. Can we be sure of this? Or does the ctlr
481 * queue up all command packets and take them in sequential order?
482 * It sure would be nice if my manual stated this... /ragge
483 */
484 int
485 mtcmd(mt, cmd, count, complete)
486 struct mt_softc *mt;
487 int cmd, count, complete;
488 {
489 struct mscp *mp;
490 struct mscp_softc *mi = (void *)mt->mt_dev.dv_parent;
491 volatile int i;
492
493 mp = mscp_getcp(mi, MSCP_WAIT);
494
495 mt->mt_ioctlerr = 0;
496 mp->mscp_unit = mt->mt_hwunit;
497 mp->mscp_cmdref = -1;
498 *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
499
500 switch (cmd) {
501 case MTWEOF:
502 mp->mscp_opcode = M_OP_WRITM;
503 break;
504
505 case MTBSF:
506 mp->mscp_modifier = M_MD_REVERSE;
507 case MTFSF:
508 mp->mscp_opcode = M_OP_POS;
509 mp->mscp_seq.seq_buffer = count;
510 break;
511
512 case MTBSR:
513 mp->mscp_modifier = M_MD_REVERSE;
514 case MTFSR:
515 mp->mscp_opcode = M_OP_POS;
516 mp->mscp_modifier |= M_MD_OBJCOUNT;
517 mp->mscp_seq.seq_bytecount = count;
518 break;
519
520 case MTREW:
521 mp->mscp_opcode = M_OP_POS;
522 mp->mscp_modifier = M_MD_REWIND | M_MD_CLSEX;
523 if (complete)
524 mp->mscp_modifier |= M_MD_IMMEDIATE;
525 mt->mt_serex = 0;
526 break;
527
528 case MTOFFL:
529 mp->mscp_opcode = M_OP_AVAILABLE;
530 mp->mscp_modifier = M_MD_UNLOAD | M_MD_CLSEX;
531 mt->mt_serex = 0;
532 break;
533
534 case MTNOP:
535 mp->mscp_opcode = M_OP_GETUNITST;
536 break;
537
538 case -1: /* Clear serious exception only */
539 mp->mscp_opcode = M_OP_POS;
540 mp->mscp_modifier = M_MD_CLSEX;
541 mt->mt_serex = 0;
542 break;
543
544 default:
545 printf("Bad ioctl %x\n", cmd);
546 mp->mscp_opcode = M_OP_POS;
547 break;
548 }
549
550 i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
551 tsleep(&mt->mt_inuse, PRIBIO, "mtioctl", 0);
552 return mt->mt_ioctlerr;
553 }
554
555 /*
556 * Called from bus routines whenever a non-data transfer is finished.
557 */
558 void
559 mtcmddone(usc, mp)
560 struct device *usc;
561 struct mscp *mp;
562 {
563 struct mt_softc *mt = (void *)usc;
564
565 if (mp->mscp_status) {
566 mt->mt_ioctlerr = EIO;
567 printf("%s: bad status %x\n", mt->mt_dev.dv_xname,
568 mp->mscp_status);
569 }
570 wakeup(&mt->mt_inuse);
571 }
572