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