xref: /netbsd/sys/dev/mscp/mscp_tape.c (revision bf9ec67e)
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