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