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