xref: /netbsd-src/sys/arch/hp300/dev/ct.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: ct.c,v 1.57 2009/01/13 13:35:51 yamt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1982, 1990, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  *	@(#)ct.c	8.2 (Berkeley) 1/12/94
61  */
62 
63 /*
64  * CS80 cartridge tape driver (9144, 88140, 9145)
65  *
66  * Reminder:
67  *	C_CC bit (character count option) when used in the CS/80 command
68  *	'set options' will cause the tape not to stream.
69  *
70  * TODO:
71  *	make filesystem compatible
72  *	make block mode work according to mtio(4) spec. (if possible)
73  *	merge with cs80 disk driver
74  *	finish support of 9145
75  */
76 
77 #include <sys/cdefs.h>
78 __KERNEL_RCSID(0, "$NetBSD: ct.c,v 1.57 2009/01/13 13:35:51 yamt Exp $");
79 
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/buf.h>
83 #include <sys/bufq.h>
84 #include <sys/conf.h>
85 #include <sys/device.h>
86 #include <sys/ioctl.h>
87 #include <sys/mtio.h>
88 #include <sys/proc.h>
89 #include <sys/tprintf.h>
90 
91 #include <hp300/dev/hpibvar.h>
92 
93 #include <hp300/dev/ctreg.h>
94 
95 #include "ioconf.h"
96 
97 /* number of eof marks to remember */
98 #define EOFS	128
99 
100 struct	ct_softc {
101 	device_t sc_dev;
102 	int	sc_slave;		/* HP-IB slave ID */
103 	int	sc_punit;		/* physical unit */
104 	struct	ct_iocmd sc_ioc;
105 	struct	ct_rscmd sc_rsc;
106 	struct	ct_stat sc_stat;
107 	struct	ct_ssmcmd sc_ssmc;
108 	struct	ct_srcmd sc_src;
109 	struct	ct_soptcmd sc_soptc;
110 	struct	ct_ulcmd sc_ul;
111 	struct	ct_wfmcmd sc_wfm;
112 	struct	ct_clearcmd sc_clear;
113 	struct	bufq_state *sc_tab;
114 	int	sc_active;
115 	struct	buf *sc_bp;
116 	struct	buf sc_bufstore;	/* XXX */
117 	int	sc_blkno;
118 	int	sc_cmd;
119 	int	sc_resid;
120 	char	*sc_addr;
121 	int	sc_flags;
122 	short	sc_type;
123 	tpr_t	sc_tpr;
124 	struct	hpibqueue sc_hq;	/* entry on hpib job queue */
125 	int	sc_eofp;
126 	int	sc_eofs[EOFS];
127 };
128 
129 /* flags */
130 #define	CTF_OPEN	0x01
131 #define	CTF_ALIVE	0x02
132 #define	CTF_WRT		0x04
133 #define	CTF_CMD		0x08
134 #define	CTF_IO		0x10
135 #define	CTF_BEOF	0x20
136 #define	CTF_AEOF	0x40
137 #define	CTF_EOT		0x80
138 #define	CTF_STATWAIT	0x100
139 #define CTF_CANSTREAM	0x200
140 #define	CTF_WRTTN	0x400
141 
142 static int	ctmatch(device_t, cfdata_t, void *);
143 static void	ctattach(device_t, device_t, void *);
144 
145 CFATTACH_DECL_NEW(ct, sizeof(struct ct_softc),
146     ctmatch, ctattach, NULL, NULL);
147 
148 static dev_type_open(ctopen);
149 static dev_type_close(ctclose);
150 static dev_type_read(ctread);
151 static dev_type_write(ctwrite);
152 static dev_type_ioctl(ctioctl);
153 static dev_type_strategy(ctstrategy);
154 
155 const struct bdevsw ct_bdevsw = {
156 	ctopen, ctclose, ctstrategy, ctioctl, nodump, nosize, D_TAPE
157 };
158 
159 const struct cdevsw ct_cdevsw = {
160 	ctopen, ctclose, ctread, ctwrite, ctioctl,
161 	nostop, notty, nopoll, nommap, nokqfilter, D_TAPE
162 };
163 
164 static int	ctident(device_t, struct ct_softc *,
165 		    struct hpibbus_attach_args *);
166 
167 static void	ctreset(struct ct_softc *);
168 static void	ctaddeof(struct ct_softc *);
169 static void	ctustart(struct ct_softc *);
170 static void	cteof(struct ct_softc *, struct buf *);
171 static void	ctdone(struct ct_softc *, struct buf *);
172 
173 static void	ctstart(void *);
174 static void	ctgo(void *);
175 static void	ctintr(void *);
176 
177 static void	ctcommand(dev_t, int, int);
178 
179 static const struct ctinfo {
180 	short	hwid;
181 	short	punit;
182 	const char *desc;
183 } ctinfo[] = {
184 	{ CT7946ID,	1,	"7946A"	},
185 	{ CT7912PID,	1,	"7912P"	},
186 	{ CT7914PID,	1,	"7914P"	},
187 	{ CT9144ID,	0,	"9144"	},
188 	{ CT9145ID,	0,	"9145"	},
189 	{ CT35401ID,	0,	"35401A"},
190 };
191 static const int nctinfo = __arraycount(ctinfo);
192 
193 #define	CT_NOREW	4
194 #define	CT_STREAM	8
195 #define	UNIT(x)		(minor(x) & 3)
196 #define	ctpunit(x)	((x) & 7)
197 
198 #ifdef DEBUG
199 int ctdebug = 0;
200 #define CDB_FILES	0x01
201 #define CT_BSF		0x02
202 #endif
203 
204 static int
205 ctmatch(device_t parent, cfdata_t cf, void *aux)
206 {
207 	struct hpibbus_attach_args *ha = aux;
208 
209 	return ctident(parent, NULL, ha);
210 }
211 
212 static void
213 ctattach(device_t parent, device_t self, void *aux)
214 {
215 	struct ct_softc *sc = device_private(self);
216 	struct hpibbus_attach_args *ha = aux;
217 
218 	sc->sc_dev = self;
219 	if (ctident(parent, sc, ha) == 0) {
220 		aprint_error(": didn't respond to describe command!\n");
221 		return;
222 	}
223 
224 	sc->sc_slave = ha->ha_slave;
225 	sc->sc_punit = ha->ha_punit;
226 
227 	bufq_alloc(&sc->sc_tab, "fcfs", 0);
228 
229 	/* Initialize hpib job queue entry. */
230 	sc->sc_hq.hq_softc = sc;
231 	sc->sc_hq.hq_slave = sc->sc_slave;
232 	sc->sc_hq.hq_start = ctstart;
233 	sc->sc_hq.hq_go = ctgo;
234 	sc->sc_hq.hq_intr = ctintr;
235 
236 	ctreset(sc);
237 	sc->sc_flags |= CTF_ALIVE;
238 }
239 
240 static int
241 ctident(device_t parent, struct ct_softc *sc, struct hpibbus_attach_args *ha)
242 {
243 	struct ct_describe desc;
244 	u_char stat, cmd[3];
245 	char name[7];
246 	int i, id, n, type, canstream;
247 
248 	type = canstream = 0;
249 
250 	/* Verify that we have a CS80 device. */
251 	if ((ha->ha_id & 0x200) == 0)
252 		return 0;
253 
254 	/* Is it one of the tapes we support? */
255 	for (id = 0; id < nctinfo; id++)
256 		if (ha->ha_id == ctinfo[id].hwid)
257 			break;
258 	if (id == nctinfo)
259 		return 0;
260 
261 	ha->ha_punit = ctinfo[id].punit;
262 
263 	/*
264 	 * So far, so good.  Get drive parameters.  Note command
265 	 * is always issued to unit 0.
266 	 */
267 	cmd[0] = C_SUNIT(0);
268 	cmd[1] = C_SVOL(0);
269 	cmd[2] = C_DESC;
270 	hpibsend(device_unit(parent), ha->ha_slave, C_CMD, cmd, sizeof(cmd));
271 	hpibrecv(device_unit(parent), ha->ha_slave, C_EXEC, &desc, 37);
272 	hpibrecv(device_unit(parent), ha->ha_slave, C_QSTAT, &stat,
273 		 sizeof(stat));
274 
275 	memset(name, 0, sizeof(name));
276 	if (stat == 0) {
277 		n = desc.d_name;
278 		for (i = 5; i >= 0; i--) {
279 			name[i] = (n & 0xf) + '0';
280 			n >>= 4;
281 		}
282 	}
283 
284 	switch (ha->ha_id) {
285 	case CT7946ID:
286 		if (memcmp(name, "079450", 6) == 0)
287 			return 0;		/* not really a 7946 */
288 		/* fall into... */
289 	case CT9144ID:
290 	case CT9145ID:
291 	case CT35401ID:
292 		type = CT9144;
293 		canstream = 1;
294 		break;
295 
296 	case CT7912PID:
297 	case CT7914PID:
298 		type = CT88140;
299 		break;
300 	}
301 
302 	if (sc != NULL) {
303 		sc->sc_type = type;
304 		sc->sc_flags = canstream ? CTF_CANSTREAM : 0;
305 		aprint_normal(": %s %stape\n", ctinfo[id].desc,
306 		    canstream ? "streaming " : "");
307 	}
308 
309 	return 1;
310 }
311 
312 static void
313 ctreset(struct ct_softc *sc)
314 {
315 	int ctlr, slave;
316 	uint8_t stat;
317 
318 	ctlr = device_unit(device_parent(sc->sc_dev));
319 	slave = sc->sc_slave;
320 
321 	sc->sc_clear.unit = C_SUNIT(sc->sc_punit);
322 	sc->sc_clear.cmd = C_CLEAR;
323 	hpibsend(ctlr, slave, C_TCMD, &sc->sc_clear, sizeof(sc->sc_clear));
324 	hpibswait(ctlr, slave);
325 	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
326 
327 	sc->sc_src.unit = C_SUNIT(CTCTLR);
328 	sc->sc_src.nop = C_NOP;
329 	sc->sc_src.cmd = C_SREL;
330 	sc->sc_src.param = C_REL;
331 	hpibsend(ctlr, slave, C_CMD, &sc->sc_src, sizeof(sc->sc_src));
332 	hpibswait(ctlr, slave);
333 	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
334 
335 	sc->sc_ssmc.unit = C_SUNIT(sc->sc_punit);
336 	sc->sc_ssmc.cmd = C_SSM;
337 	sc->sc_ssmc.refm = REF_MASK;
338 	sc->sc_ssmc.fefm = FEF_MASK;
339 	sc->sc_ssmc.aefm = AEF_MASK;
340 	sc->sc_ssmc.iefm = IEF_MASK;
341 	hpibsend(ctlr, slave, C_CMD, &sc->sc_ssmc, sizeof(sc->sc_ssmc));
342 	hpibswait(ctlr, slave);
343 	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
344 
345 	sc->sc_soptc.unit = C_SUNIT(sc->sc_punit);
346 	sc->sc_soptc.nop = C_NOP;
347 	sc->sc_soptc.cmd = C_SOPT;
348 	sc->sc_soptc.opt = C_SPAR;
349 	hpibsend(ctlr, slave, C_CMD, &sc->sc_soptc, sizeof(sc->sc_soptc));
350 	hpibswait(ctlr, slave);
351 	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
352 }
353 
354 /*ARGSUSED*/
355 static int
356 ctopen(dev_t dev, int flag, int type, struct lwp *l)
357 {
358 	struct ct_softc *sc;
359 	uint8_t stat;
360 	int cc, ctlr, slave;
361 
362 	sc = device_lookup_private(&ct_cd, UNIT(dev));
363 	if (sc == NULL)
364 		return ENXIO;
365 
366 	if ((sc->sc_flags & CTF_ALIVE) == 0)
367 		return ENXIO;
368 
369 	if (sc->sc_flags & CTF_OPEN)
370 		return EBUSY;
371 
372 	ctlr = device_unit(device_parent(sc->sc_dev));
373 	slave = sc->sc_slave;
374 
375 	sc->sc_soptc.unit = C_SUNIT(sc->sc_punit);
376 	sc->sc_soptc.nop = C_NOP;
377 	sc->sc_soptc.cmd = C_SOPT;
378 	if ((dev & CT_STREAM) && (sc->sc_flags & CTF_CANSTREAM))
379 		sc->sc_soptc.opt = C_SPAR | C_IMRPT;
380 	else
381 		sc->sc_soptc.opt = C_SPAR;
382 
383 	/*
384 	 * Check the return of hpibsend() and hpibswait().
385 	 * Drive could be loading/unloading a tape. If not checked,
386 	 * driver hangs.
387 	 */
388 	cc = hpibsend(ctlr, slave, C_CMD, &sc->sc_soptc, sizeof(sc->sc_soptc));
389 	if (cc != sizeof(sc->sc_soptc))
390 		return EBUSY;
391 
392 	hpibswait(ctlr, slave);
393 	cc = hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
394 	if (cc != sizeof(stat))
395 		return EBUSY;
396 
397 	sc->sc_tpr = tprintf_open(l->l_proc);
398 	sc->sc_flags |= CTF_OPEN;
399 	return 0;
400 }
401 
402 /*ARGSUSED*/
403 static int
404 ctclose(dev_t dev, int flag, int fmt, struct lwp *l)
405 {
406 	struct ct_softc *sc = device_lookup_private(&ct_cd,UNIT(dev));
407 
408 	if ((sc->sc_flags & (CTF_WRT|CTF_WRTTN)) == (CTF_WRT|CTF_WRTTN) &&
409 	    (sc->sc_flags & CTF_EOT) == 0 ) { /* XXX return error if EOT ?? */
410 		ctcommand(dev, MTWEOF, 2);
411 		ctcommand(dev, MTBSR, 1);
412 		if (sc->sc_eofp == EOFS - 1)
413 			sc->sc_eofs[EOFS - 1]--;
414 		else
415 			sc->sc_eofp--;
416 #ifdef DEBUG
417 		if(ctdebug & CT_BSF)
418 			printf("%s: ctclose backup eofs prt %d blk %d\n",
419 			    device_xname(sc->sc_dev), sc->sc_eofp,
420 			    sc->sc_eofs[sc->sc_eofp]);
421 #endif
422 	}
423 	if ((minor(dev) & CT_NOREW) == 0)
424 		ctcommand(dev, MTREW, 1);
425 	sc->sc_flags &= ~(CTF_OPEN | CTF_WRT | CTF_WRTTN);
426 	tprintf_close(sc->sc_tpr);
427 #ifdef DEBUG
428 	if (ctdebug & CDB_FILES)
429 		printf("ctclose: flags %x\n", sc->sc_flags);
430 #endif
431 	return 0;	/* XXX */
432 }
433 
434 static void
435 ctcommand(dev_t dev, int cmd, int cnt)
436 {
437 	struct ct_softc *sc = device_lookup_private(&ct_cd,UNIT(dev));
438 	struct buf *bp = &sc->sc_bufstore;
439 	struct buf *nbp = 0;
440 
441 	if (cmd == MTBSF && sc->sc_eofp == EOFS - 1) {
442 		cnt = sc->sc_eofs[EOFS - 1] - cnt;
443 		ctcommand(dev, MTREW, 1);
444 		ctcommand(dev, MTFSF, cnt);
445 		cnt = 2;
446 		cmd = MTBSR;
447 	}
448 
449 	if (cmd == MTBSF && sc->sc_eofp - cnt < 0) {
450 		cnt = 1;
451 		cmd = MTREW;
452 	}
453 
454 	sc->sc_flags |= CTF_CMD;
455 	sc->sc_bp = bp;
456 	sc->sc_cmd = cmd;
457 	bp->b_dev = dev;
458 	if (cmd == MTFSF) {
459 		nbp = (struct buf *)geteblk(MAXBSIZE);
460 		bp->b_data = nbp->b_data;
461 		bp->b_bcount = MAXBSIZE;
462 	}
463 
464 	while (cnt-- > 0) {
465 		bp->b_cflags = BC_BUSY;
466 		if (cmd == MTBSF) {
467 			sc->sc_blkno = sc->sc_eofs[sc->sc_eofp];
468 			sc->sc_eofp--;
469 #ifdef DEBUG
470 			if (ctdebug & CT_BSF)
471 				printf("%s: backup eof pos %d blk %d\n",
472 				    device_xname(sc->sc_dev), sc->sc_eofp,
473 				    sc->sc_eofs[sc->sc_eofp]);
474 #endif
475 		}
476 		ctstrategy(bp);
477 		biowait(bp);
478 	}
479 	bp->b_flags = 0;
480 	sc->sc_flags &= ~CTF_CMD;
481 	if (nbp)
482 		brelse(nbp, 0);
483 }
484 
485 static void
486 ctstrategy(struct buf *bp)
487 {
488 	int s;
489 	struct ct_softc *sc;
490 
491 	sc = device_lookup_private(&ct_cd, UNIT(bp->b_dev));
492 
493 	s = splbio();
494 	bufq_put(sc->sc_tab, bp);
495 	if (sc->sc_active == 0) {
496 		sc->sc_active = 1;
497 		ctustart(sc);
498 	}
499 	splx(s);
500 }
501 
502 static void
503 ctustart(struct ct_softc *sc)
504 {
505 	struct buf *bp;
506 
507 	bp = bufq_peek(sc->sc_tab);
508 	sc->sc_addr = bp->b_data;
509 	sc->sc_resid = bp->b_bcount;
510 	if (hpibreq(device_parent(sc->sc_dev), &sc->sc_hq))
511 		ctstart(sc);
512 }
513 
514 static void
515 ctstart(void *arg)
516 {
517 	struct ct_softc *sc = arg;
518 	struct buf *bp;
519 	int i, ctlr, slave;
520 
521 	ctlr = device_unit(device_parent(sc->sc_dev));
522 	slave = sc->sc_slave;
523 
524 	bp = bufq_peek(sc->sc_tab);
525 	if ((sc->sc_flags & CTF_CMD) && sc->sc_bp == bp) {
526 		switch(sc->sc_cmd) {
527 		case MTFSF:
528 			bp->b_flags |= B_READ;
529 			goto mustio;
530 
531 		case MTBSF:
532 			goto gotaddr;
533 
534 		case MTOFFL:
535 			sc->sc_blkno = 0;
536 			sc->sc_ul.unit = C_SUNIT(sc->sc_punit);
537 			sc->sc_ul.cmd = C_UNLOAD;
538 			hpibsend(ctlr, slave, C_CMD, &sc->sc_ul,
539 			    sizeof(sc->sc_ul));
540 			break;
541 
542 		case MTWEOF:
543 			sc->sc_blkno++;
544 			sc->sc_flags |= CTF_WRT;
545 			sc->sc_wfm.unit = C_SUNIT(sc->sc_punit);
546 			sc->sc_wfm.cmd = C_WFM;
547 			hpibsend(ctlr, slave, C_CMD, &sc->sc_wfm,
548 			    sizeof(sc->sc_wfm));
549 			ctaddeof(sc);
550 			break;
551 
552 		case MTBSR:
553 			sc->sc_blkno--;
554 			goto gotaddr;
555 
556 		case MTFSR:
557 			sc->sc_blkno++;
558 			goto gotaddr;
559 
560 		case MTREW:
561 			sc->sc_blkno = 0;
562 #ifdef DEBUG
563 			if(ctdebug & CT_BSF)
564 				printf("%s: clearing eofs\n",
565 				    device_xname(sc->sc_dev));
566 #endif
567 			for (i=0; i<EOFS; i++)
568 				sc->sc_eofs[i] = 0;
569 			sc->sc_eofp = 0;
570 
571 gotaddr:
572 			sc->sc_ioc.saddr = C_SADDR;
573 			sc->sc_ioc.addr0 = 0;
574 			sc->sc_ioc.addr = sc->sc_blkno;
575 			sc->sc_ioc.unit = C_SUNIT(sc->sc_punit);
576 			sc->sc_ioc.nop2 = C_NOP;
577 			sc->sc_ioc.slen = C_SLEN;
578 			sc->sc_ioc.len = 0;
579 			sc->sc_ioc.nop3 = C_NOP;
580 			sc->sc_ioc.cmd = C_READ;
581 			hpibsend(ctlr, slave, C_CMD, &sc->sc_ioc,
582 			    sizeof(sc->sc_ioc));
583 			break;
584 		}
585 	} else {
586 mustio:
587 		if ((bp->b_flags & B_READ) &&
588 		    sc->sc_flags & (CTF_BEOF|CTF_EOT)) {
589 #ifdef DEBUG
590 			if (ctdebug & CDB_FILES)
591 				printf("ctstart: before flags %x\n",
592 				    sc->sc_flags);
593 #endif
594 			if (sc->sc_flags & CTF_BEOF) {
595 				sc->sc_flags &= ~CTF_BEOF;
596 				sc->sc_flags |= CTF_AEOF;
597 #ifdef DEBUG
598 				if (ctdebug & CDB_FILES)
599 					printf("ctstart: after flags %x\n",
600 					    sc->sc_flags);
601 #endif
602 			}
603 			bp->b_resid = bp->b_bcount;
604 			ctdone(sc, bp);
605 			return;
606 		}
607 		sc->sc_flags |= CTF_IO;
608 		sc->sc_ioc.unit = C_SUNIT(sc->sc_punit);
609 		sc->sc_ioc.saddr = C_SADDR;
610 		sc->sc_ioc.addr0 = 0;
611 		sc->sc_ioc.addr = sc->sc_blkno;
612 		sc->sc_ioc.nop2 = C_NOP;
613 		sc->sc_ioc.slen = C_SLEN;
614 		sc->sc_ioc.len = sc->sc_resid;
615 		sc->sc_ioc.nop3 = C_NOP;
616 		if (bp->b_flags & B_READ)
617 			sc->sc_ioc.cmd = C_READ;
618 		else {
619 			sc->sc_ioc.cmd = C_WRITE;
620 			sc->sc_flags |= (CTF_WRT | CTF_WRTTN);
621 		}
622 		hpibsend(ctlr, slave, C_CMD, &sc->sc_ioc, sizeof(sc->sc_ioc));
623 	}
624 	hpibawait(ctlr);
625 }
626 
627 static void
628 ctgo(void *arg)
629 {
630 	struct ct_softc *sc = arg;
631 	struct buf *bp;
632 	int rw;
633 
634 	bp = bufq_peek(sc->sc_tab);
635 	rw = bp->b_flags & B_READ;
636 	hpibgo(device_unit(device_parent(sc->sc_dev)), sc->sc_slave, C_EXEC,
637 	    sc->sc_addr, sc->sc_resid, rw, rw != 0);
638 }
639 
640 /*
641  * Hideous grue to handle EOF/EOT (mostly for reads)
642  */
643 static void
644 cteof(struct ct_softc *sc, struct buf *bp)
645 {
646 	long blks;
647 
648 	/*
649 	 * EOT on a write is an error.
650 	 */
651 	if ((bp->b_flags & B_READ) == 0) {
652 		bp->b_resid = bp->b_bcount;
653 		bp->b_error = ENOSPC;
654 		sc->sc_flags |= CTF_EOT;
655 		return;
656 	}
657 	/*
658 	 * Use returned block position to determine how many blocks
659 	 * we really read and update b_resid.
660 	 */
661 	blks = sc->sc_stat.c_blk - sc->sc_blkno - 1;
662 #ifdef DEBUG
663 	if (ctdebug & CDB_FILES)
664 		printf("cteof: bc %d oblk %d nblk %ld read %ld, resid %ld\n",
665 		       bp->b_bcount, sc->sc_blkno, sc->sc_stat.c_blk,
666 		       blks, bp->b_bcount - CTKTOB(blks));
667 #endif
668 	if (blks == -1) { /* 9145 on EOF does not change sc_stat.c_blk */
669 		blks = 0;
670 		sc->sc_blkno++;
671 	}
672 	else {
673 		sc->sc_blkno = sc->sc_stat.c_blk;
674 	}
675 	bp->b_resid = bp->b_bcount - CTKTOB(blks);
676 	/*
677 	 * If we are at physical EOV or were after an EOF,
678 	 * we are now at logical EOT.
679 	 */
680 	if ((sc->sc_stat.c_aef & AEF_EOV) ||
681 	    (sc->sc_flags & CTF_AEOF)) {
682 		sc->sc_flags |= CTF_EOT;
683 		sc->sc_flags &= ~(CTF_AEOF|CTF_BEOF);
684 	}
685 	/*
686 	 * If we were before an EOF or we have just completed a FSF,
687 	 * we are now after EOF.
688 	 */
689 	else if ((sc->sc_flags & CTF_BEOF) ||
690 		 ((sc->sc_flags & CTF_CMD) && sc->sc_cmd == MTFSF)) {
691 		sc->sc_flags |= CTF_AEOF;
692 		sc->sc_flags &= ~CTF_BEOF;
693 	}
694 	/*
695 	 * Otherwise if we read something we are now before EOF
696 	 * (and no longer after EOF).
697 	 */
698 	else if (blks) {
699 		sc->sc_flags |= CTF_BEOF;
700 		sc->sc_flags &= ~CTF_AEOF;
701 	}
702 	/*
703 	 * Finally, if we didn't read anything we just passed an EOF
704 	 */
705 	else
706 		sc->sc_flags |= CTF_AEOF;
707 #ifdef DEBUG
708 	if (ctdebug & CDB_FILES)
709 		printf("cteof: leaving flags %x\n", sc->sc_flags);
710 #endif
711 }
712 
713 /* ARGSUSED */
714 static void
715 ctintr(void *arg)
716 {
717 	struct ct_softc *sc = arg;
718 	struct buf *bp;
719 	uint8_t stat;
720 	int ctlr, slave, unit;
721 
722 	ctlr = device_unit(device_parent(sc->sc_dev));
723 	slave = sc->sc_slave;
724 	unit = device_unit(sc->sc_dev);
725 
726 	bp = bufq_peek(sc->sc_tab);
727 	if (bp == NULL) {
728 		printf("%s: bp == NULL\n", device_xname(sc->sc_dev));
729 		return;
730 	}
731 	if (sc->sc_flags & CTF_IO) {
732 		sc->sc_flags &= ~CTF_IO;
733 		if (hpibustart(ctlr))
734 			ctgo(sc);
735 		return;
736 	}
737 	if ((sc->sc_flags & CTF_STATWAIT) == 0) {
738 		if (hpibpptest(ctlr, slave) == 0) {
739 			sc->sc_flags |= CTF_STATWAIT;
740 			hpibawait(ctlr);
741 			return;
742 		}
743 	} else
744 		sc->sc_flags &= ~CTF_STATWAIT;
745 	hpibrecv(ctlr, slave, C_QSTAT, &stat, 1);
746 #ifdef DEBUG
747 	if (ctdebug & CDB_FILES)
748 		printf("ctintr: before flags %x\n", sc->sc_flags);
749 #endif
750 	if (stat) {
751 		sc->sc_rsc.unit = C_SUNIT(sc->sc_punit);
752 		sc->sc_rsc.cmd = C_STATUS;
753 		hpibsend(ctlr, slave, C_CMD, &sc->sc_rsc, sizeof(sc->sc_rsc));
754 		hpibrecv(ctlr, slave, C_EXEC, &sc->sc_stat,
755 		    sizeof(sc->sc_stat));
756 		hpibrecv(ctlr, slave, C_QSTAT, &stat, 1);
757 #ifdef DEBUG
758 		if (ctdebug & CDB_FILES)
759 			printf("ctintr: return stat 0x%x, A%x F%x blk %ld\n",
760 			       stat, sc->sc_stat.c_aef,
761 			       sc->sc_stat.c_fef, sc->sc_stat.c_blk);
762 #endif
763 		if (stat == 0) {
764 			if (sc->sc_stat.c_aef & (AEF_EOF | AEF_EOV)) {
765 				cteof(sc, bp);
766 				ctaddeof(sc);
767 				goto done;
768 			}
769 			if (sc->sc_stat.c_fef & FEF_PF) {
770 				ctreset(sc);
771 				ctstart(sc);
772 				return;
773 			}
774 			if (sc->sc_stat.c_fef & FEF_REXMT) {
775 				ctstart(sc);
776 				return;
777 			}
778 			if (sc->sc_stat.c_aef & 0x5800) {
779 				if (sc->sc_stat.c_aef & 0x4000)
780 					tprintf(sc->sc_tpr,
781 					    "%s: uninitialized media\n",
782 					    device_xname(sc->sc_dev));
783 				if (sc->sc_stat.c_aef & 0x1000)
784 					tprintf(sc->sc_tpr,
785 					    "%s: not ready\n",
786 					    device_xname(sc->sc_dev));
787 				if (sc->sc_stat.c_aef & 0x0800)
788 					tprintf(sc->sc_tpr,
789 					    "%s: write protect\n",
790 					    device_xname(sc->sc_dev));
791 			} else {
792 				printf("%s err: v%d u%d ru%d bn%ld, ",
793 				    device_xname(sc->sc_dev),
794 				       (sc->sc_stat.c_vu >> 4) & 0xF,
795 				       sc->sc_stat.c_vu & 0xF,
796 				       sc->sc_stat.c_pend,
797 				       sc->sc_stat.c_blk);
798 				printf("R0x%x F0x%x A0x%x I0x%x\n",
799 				       sc->sc_stat.c_ref,
800 				       sc->sc_stat.c_fef,
801 				       sc->sc_stat.c_aef,
802 				       sc->sc_stat.c_ief);
803 			}
804 		} else
805 			printf("%s: request status failed\n",
806 			    device_xname(sc->sc_dev));
807 		bp->b_error = EIO;
808 		goto done;
809 	} else
810 		bp->b_resid = 0;
811 	if (sc->sc_flags & CTF_CMD) {
812 		switch (sc->sc_cmd) {
813 		case MTFSF:
814 			sc->sc_flags &= ~(CTF_BEOF|CTF_AEOF);
815 			sc->sc_blkno += CTBTOK(sc->sc_resid);
816 			ctstart(sc);
817 			return;
818 		case MTBSF:
819 			sc->sc_flags &= ~(CTF_AEOF|CTF_BEOF|CTF_EOT);
820 			break;
821 		case MTBSR:
822 			sc->sc_flags &= ~CTF_BEOF;
823 			if (sc->sc_flags & CTF_EOT) {
824 				sc->sc_flags |= CTF_AEOF;
825 				sc->sc_flags &= ~CTF_EOT;
826 			} else if (sc->sc_flags & CTF_AEOF) {
827 				sc->sc_flags |= CTF_BEOF;
828 				sc->sc_flags &= ~CTF_AEOF;
829 			}
830 			break;
831 		case MTWEOF:
832 			sc->sc_flags &= ~CTF_BEOF;
833 			if (sc->sc_flags & (CTF_AEOF|CTF_EOT)) {
834 				sc->sc_flags |= CTF_EOT;
835 				sc->sc_flags &= ~CTF_AEOF;
836 			} else
837 				sc->sc_flags |= CTF_AEOF;
838 			break;
839 		case MTREW:
840 		case MTOFFL:
841 			sc->sc_flags &= ~(CTF_BEOF|CTF_AEOF|CTF_EOT);
842 			break;
843 		}
844 	} else {
845 		sc->sc_flags &= ~CTF_AEOF;
846 		sc->sc_blkno += CTBTOK(sc->sc_resid);
847 	}
848 done:
849 #ifdef DEBUG
850 	if (ctdebug & CDB_FILES)
851 		printf("ctintr: after flags %x\n", sc->sc_flags);
852 #endif
853 	ctdone(sc, bp);
854 }
855 
856 static void
857 ctdone(struct ct_softc *sc, struct buf *bp)
858 {
859 
860 	(void)bufq_get(sc->sc_tab);
861 	biodone(bp);
862 	hpibfree(device_parent(sc->sc_dev), &sc->sc_hq);
863 	if (bufq_peek(sc->sc_tab) == NULL) {
864 		sc->sc_active = 0;
865 		return;
866 	}
867 	ctustart(sc);
868 }
869 
870 static int
871 ctread(dev_t dev, struct uio *uio, int flags)
872 {
873 
874 	return physio(ctstrategy, NULL, dev, B_READ, minphys, uio);
875 }
876 
877 static int
878 ctwrite(dev_t dev, struct uio *uio, int flags)
879 {
880 
881 	/* XXX: check for hardware write-protect? */
882 	return physio(ctstrategy, NULL, dev, B_WRITE, minphys, uio);
883 }
884 
885 /*ARGSUSED*/
886 static int
887 ctioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
888 {
889 	struct mtop *op;
890 	int cnt;
891 
892 	switch (cmd) {
893 
894 	case MTIOCTOP:
895 		op = (struct mtop *)data;
896 		switch(op->mt_op) {
897 
898 		case MTWEOF:
899 		case MTFSF:
900 		case MTBSR:
901 		case MTBSF:
902 		case MTFSR:
903 			cnt = op->mt_count;
904 			break;
905 
906 		case MTREW:
907 		case MTOFFL:
908 			cnt = 1;
909 			break;
910 
911 		default:
912 			return EINVAL;
913 		}
914 		ctcommand(dev, op->mt_op, cnt);
915 		break;
916 
917 	case MTIOCGET:
918 		break;
919 
920 	default:
921 		return EINVAL;
922 	}
923 	return 0;
924 }
925 
926 static void
927 ctaddeof(struct ct_softc *sc)
928 {
929 
930 	if (sc->sc_eofp == EOFS - 1)
931 		sc->sc_eofs[EOFS - 1]++;
932 	else {
933 		sc->sc_eofp++;
934 		if (sc->sc_eofp == EOFS - 1)
935 			sc->sc_eofs[EOFS - 1] = EOFS;
936 		else
937 			/* save blkno */
938 			sc->sc_eofs[sc->sc_eofp] = sc->sc_blkno - 1;
939 	}
940 #ifdef DEBUG
941 	if (ctdebug & CT_BSF)
942 		printf("%s: add eof pos %d blk %d\n",
943 		       device_xname(sc->sc_dev), sc->sc_eofp,
944 		       sc->sc_eofs[sc->sc_eofp]);
945 #endif
946 }
947