1 |
199 |
simons |
/* $Id: tpqic02.c,v 1.1.1.1 2001-09-10 07:44:17 simons Exp $
|
2 |
|
|
*
|
3 |
|
|
* Driver for tape drive support for Linux-i386 1.1.58
|
4 |
|
|
*
|
5 |
|
|
* Copyright (c) 1992, 1993, 1994 by H. H. Bergman. All rights reserved.
|
6 |
|
|
* Current e-mail address: hennus@sky.ow.org [This is a UUCP link.]
|
7 |
|
|
* [If you are unable to reach me directly, try the TAPE mailing list
|
8 |
|
|
* channel on linux-activists@niksula.hut.fi using "X-Mn-Key: TAPE" as
|
9 |
|
|
* the first line in your message.]
|
10 |
|
|
*
|
11 |
|
|
* Distribution of this program in executable form is only allowed if
|
12 |
|
|
* all of the corresponding source files are made available through the same
|
13 |
|
|
* medium at no extra cost.
|
14 |
|
|
*
|
15 |
|
|
* I will not accept any responsibility for damage caused directly or
|
16 |
|
|
* indirectly by this program, or code derived from this program.
|
17 |
|
|
*
|
18 |
|
|
* Use this code at your own risk. Don't blame me if it destroys your data!
|
19 |
|
|
* Make sure you have a backup before you try this code.
|
20 |
|
|
*
|
21 |
|
|
* If you make changes to my code and redistribute it in source or binary
|
22 |
|
|
* form you must make it clear to even casual users of your code that you
|
23 |
|
|
* have modified my code, clearly point out what the changes exactly are
|
24 |
|
|
* (preferably in the form of a context diff file), how to undo your changes,
|
25 |
|
|
* where the original can be obtained, and that complaints/requests about the
|
26 |
|
|
* modified code should be directed to you instead of me.
|
27 |
|
|
*
|
28 |
|
|
* This driver was partially inspired by the 'wt' driver in the 386BSD
|
29 |
|
|
* source distribution, which carries the following copyright notice:
|
30 |
|
|
*
|
31 |
|
|
* Copyright (c) 1991 The Regents of the University of California.
|
32 |
|
|
* All rights reserved.
|
33 |
|
|
*
|
34 |
|
|
* You are not allowed to change this line nor the text above.
|
35 |
|
|
*
|
36 |
|
|
* $Log: not supported by cvs2svn $
|
37 |
|
|
* Revision 1.1.1.1 2001/07/02 17:58:25 simons
|
38 |
|
|
* Initial revision
|
39 |
|
|
*
|
40 |
|
|
* Revision 0.4.1.5 1994/10/29 02:46:13 root
|
41 |
|
|
* Minor cleanups.
|
42 |
|
|
*
|
43 |
|
|
* Revision 0.4.1.4 1994/07/21 02:15:45 root
|
44 |
|
|
* ifdef'd DDI. Exception masks.
|
45 |
|
|
*
|
46 |
|
|
* Revision 0.4.1.3 1994/05/03 01:49:09 root
|
47 |
|
|
* Initial attempt at Mountain support for the Mountain 7150.
|
48 |
|
|
* Based on patches provided by Erik Jacobson.
|
49 |
|
|
*
|
50 |
|
|
* Revision 0.4.1.2 1994/03/18 21:16:50 root
|
51 |
|
|
* Many driver messages can now be turned off (runtime selectable).
|
52 |
|
|
*
|
53 |
|
|
* Revision 0.4.1.1 1994/02/16 19:47:22 root
|
54 |
|
|
* First stab at runtime debug-variable.
|
55 |
|
|
*
|
56 |
|
|
* Revision 0.4 1994/02/15 01:53:16 root
|
57 |
|
|
* DYNCONF mark II.
|
58 |
|
|
* Minor cleanups.
|
59 |
|
|
*
|
60 |
|
|
* Revision 0.3 1994/02/07 01:23:16 root
|
61 |
|
|
* More improved DYNCONF.
|
62 |
|
|
* Archive changes & some cleanups by Eddy Olk.
|
63 |
|
|
* Removed status_open, more cleanups, misc other.
|
64 |
|
|
*
|
65 |
|
|
* Revision 0.2.1.25 1994/01/24 02:01:33 root
|
66 |
|
|
* Changed tape_qic02 to QIC02_TAPE.
|
67 |
|
|
* Changes to prepare for DYNCONF.
|
68 |
|
|
*
|
69 |
|
|
* Revision 0.2.1.24 1994/01/23 07:27:18 root
|
70 |
|
|
* Attempt to remove compilation warnings, G++ bug,
|
71 |
|
|
* Linus changed TAPE_QIC02 to QIC02_TAPE.
|
72 |
|
|
*
|
73 |
|
|
* Revision 0.2.1.23 1994/01/20 23:49:28 root
|
74 |
|
|
* Changed some exception decoding stuff.
|
75 |
|
|
* TP_HAVE_SEEK, TP_HAVE_DENS. byte_swap_w() on arg, not global.
|
76 |
|
|
* Attempt to fix cartridge-changed-problem for 2150L.
|
77 |
|
|
* Release irq and dma reservations if initial reset fails.
|
78 |
|
|
*
|
79 |
|
|
* Revision 0.2.1.22 1994/01/19 20:56:55 root
|
80 |
|
|
* Speed measuring stuff moved from aperf.h to delay.h.
|
81 |
|
|
* BogoMips (tm) introduced by Linus.
|
82 |
|
|
*
|
83 |
|
|
* Revision 0.2.1.21 1993/06/18 19:04:33 root
|
84 |
|
|
* minor fixes for 0.99.10.
|
85 |
|
|
*
|
86 |
|
|
* Revision 0.2.1.20 1993/06/11 21:38:51 root
|
87 |
|
|
* Added exception code for status 0x8000 (Cypher weirdness).
|
88 |
|
|
*
|
89 |
|
|
* Revision 0.2.1.19 1993/04/19 23:13:59 root
|
90 |
|
|
* Cleanups. Changed to 0.99.8.
|
91 |
|
|
*
|
92 |
|
|
* Revision 0.2.1.18 1993/03/22 17:39:47 root
|
93 |
|
|
* Moved to 0.99.7. Added Archive MTSEEK and MTTELL support.
|
94 |
|
|
*
|
95 |
|
|
* Revision 0.2.1.17 1993/03/08 18:51:59 root
|
96 |
|
|
* Tried to `fix' write-once bug in previous release.
|
97 |
|
|
*
|
98 |
|
|
* Revision 0.2.1.16 1993/03/01 00:06:16 root
|
99 |
|
|
* Use register_chrdev() for 0.99.6.
|
100 |
|
|
*
|
101 |
|
|
* Revision 0.2.1.15 1993/02/25 00:14:25 root
|
102 |
|
|
* minor cleanups.
|
103 |
|
|
*
|
104 |
|
|
* Revision 0.2.1.14 1993/01/25 00:06:14 root
|
105 |
|
|
* Kernel udelay. Eof fixups.
|
106 |
|
|
* Removed report_ read/write dummies; have strace(1) now.
|
107 |
|
|
*
|
108 |
|
|
* Revision 0.2.1.13 1993/01/10 02:24:43 root
|
109 |
|
|
* Rewrote wait_for_ready() to use newer schedule() features.
|
110 |
|
|
* This improves performance for rewinds etc.
|
111 |
|
|
*
|
112 |
|
|
* Revision 0.2.1.12 1993/01/05 18:44:09 root
|
113 |
|
|
* Changes for 0.99.1. Fixed `restartable reads'.
|
114 |
|
|
*
|
115 |
|
|
* Revision 0.2.1.11 1992/11/28 01:19:10 root
|
116 |
|
|
* Changes to exception handling (significant).
|
117 |
|
|
* Changed returned error codes. Hopefully they're correct now.
|
118 |
|
|
* Changed declarations to please gcc-2.3.1.
|
119 |
|
|
* Patch to deal with bogus interrupts for Archive cards.
|
120 |
|
|
*
|
121 |
|
|
* Revision 0.2.1.10 1992/10/28 00:50:44 root
|
122 |
|
|
* underrun/error counter needed byte swapping.
|
123 |
|
|
*
|
124 |
|
|
* Revision 0.2.1.9 1992/10/15 17:06:01 root
|
125 |
|
|
* Removed online() stuff. Changed EOF handling.
|
126 |
|
|
*
|
127 |
|
|
* Revision 0.2.1.8 1992/10/02 22:25:48 root
|
128 |
|
|
* Removed `no_sleep' parameters (got usleep() now),
|
129 |
|
|
* cleaned up some comments.
|
130 |
|
|
*
|
131 |
|
|
* Revision 0.2.1.7 1992/09/27 01:41:55 root
|
132 |
|
|
* Changed write() to do entire user buffer in one go, rather than just
|
133 |
|
|
* a kernel-buffer sized portion each time.
|
134 |
|
|
*
|
135 |
|
|
* Revision 0.2.1.6 1992/09/21 02:15:30 root
|
136 |
|
|
* Introduced udelay() function for microsecond-delays.
|
137 |
|
|
* Trying to use get_dma_residue rather than TC flags.
|
138 |
|
|
* Patch to fill entire user buffer on reads before
|
139 |
|
|
* returning.
|
140 |
|
|
*
|
141 |
|
|
* Revision 0.2.1.5 1992/09/19 02:31:28 root
|
142 |
|
|
* Some changes based on patches by Eddy Olk to
|
143 |
|
|
* support Archive SC402/SC499R controller cards.
|
144 |
|
|
*
|
145 |
|
|
* Revision 0.2.1.4 1992/09/07 01:37:37 root
|
146 |
|
|
* Minor changes
|
147 |
|
|
*
|
148 |
|
|
* Revision 0.2.1.3 1992/08/13 00:11:02 root
|
149 |
|
|
* Added some support for Archive SC402 and SC499 cards.
|
150 |
|
|
* (Untested.)
|
151 |
|
|
*
|
152 |
|
|
* Revision 0.2.1.2 1992/08/10 02:02:36 root
|
153 |
|
|
* Changed from linux/system.h macros to asm/dma.h inline functions.
|
154 |
|
|
*
|
155 |
|
|
* Revision 0.2.1.1 1992/08/08 01:12:39 root
|
156 |
|
|
* cleaned up a bit. added stuff for selftesting.
|
157 |
|
|
* preparing for asm/dma.h instead of linux/system.h
|
158 |
|
|
*
|
159 |
|
|
* Revision 0.2 1992/08/03 20:11:30 root
|
160 |
|
|
* Changed to use new IRQ allocation. Padding now done at runtime, pads to
|
161 |
|
|
* 512 bytes. Because of this the page regs must be re-programmed every
|
162 |
|
|
* block! Added hooks for selftest commands.
|
163 |
|
|
* Moved to linux-0.97.
|
164 |
|
|
*
|
165 |
|
|
* Revision 0.1.0.5 1992/06/22 22:20:30 root
|
166 |
|
|
* moved to Linux 0.96b
|
167 |
|
|
*
|
168 |
|
|
* Revision 0.1.0.4 1992/06/18 02:00:04 root
|
169 |
|
|
* Use minor bit-7 to enable/disable printing of extra debugging info
|
170 |
|
|
* when do tape access.
|
171 |
|
|
* Added semop stuff for DMA/IRQ allocation checking. Don't think this
|
172 |
|
|
* is the right way to do it though.
|
173 |
|
|
*
|
174 |
|
|
* Revision 0.1.0.3 1992/06/01 01:57:34 root
|
175 |
|
|
* changed DRQ to DMA. added TDEBUG ifdefs to reduce output.
|
176 |
|
|
*
|
177 |
|
|
* Revision 0.1.0.2 1992/05/31 14:02:38 root
|
178 |
|
|
* changed SET_DMA_PAGE handling slightly.
|
179 |
|
|
*
|
180 |
|
|
* Revision 0.1.0.1 1992/05/27 12:12:03 root
|
181 |
|
|
* Can now use multiple files on tape (sort of).
|
182 |
|
|
* First release.
|
183 |
|
|
*
|
184 |
|
|
* Revision 0.1 1992/05/26 01:16:31 root
|
185 |
|
|
* Initial version. Copyright H. H. Bergman 1992
|
186 |
|
|
*
|
187 |
|
|
*/
|
188 |
|
|
|
189 |
|
|
/* After the legalese, now the important bits:
|
190 |
|
|
*
|
191 |
|
|
* This is a driver for the Wangtek 5150 tape drive with
|
192 |
|
|
* a QIC-02 controller for ISA-PC type computers.
|
193 |
|
|
* Hopefully it will work with other QIC-02 tape drives as well.
|
194 |
|
|
*
|
195 |
|
|
* Make sure your setup matches the configuration parameters.
|
196 |
|
|
* Also, be careful to avoid IO conflicts with other devices!
|
197 |
|
|
*/
|
198 |
|
|
|
199 |
|
|
|
200 |
|
|
/*
|
201 |
|
|
#define TDEBUG
|
202 |
|
|
*/
|
203 |
|
|
|
204 |
|
|
#define REALLY_SLOW_IO /* it sure is ... */
|
205 |
|
|
|
206 |
|
|
#include <linux/sched.h>
|
207 |
|
|
#include <linux/timer.h>
|
208 |
|
|
#include <linux/fs.h>
|
209 |
|
|
#include <linux/kernel.h>
|
210 |
|
|
#include <linux/major.h>
|
211 |
|
|
#include <linux/errno.h>
|
212 |
|
|
#include <linux/mtio.h>
|
213 |
|
|
#include <linux/fcntl.h>
|
214 |
|
|
#include <linux/delay.h>
|
215 |
|
|
#include <linux/tpqic02.h>
|
216 |
|
|
#include <linux/config.h>
|
217 |
|
|
#include <linux/mm.h>
|
218 |
|
|
|
219 |
|
|
#include <asm/dma.h>
|
220 |
|
|
#include <asm/system.h>
|
221 |
|
|
#include <asm/io.h>
|
222 |
|
|
#include <asm/segment.h>
|
223 |
|
|
|
224 |
|
|
/* We really shouldn't be using this define.. */
|
225 |
|
|
#define IOCCMD_MASK 0x0000ffff
|
226 |
|
|
|
227 |
|
|
/* check existence of required configuration parameters */
|
228 |
|
|
#if !defined(QIC02_CMD_PORT) || \
|
229 |
|
|
!defined(QIC02_TAPE_IRQ) || \
|
230 |
|
|
!defined(QIC02_TAPE_DMA)
|
231 |
|
|
#error qic02_tape configuration error
|
232 |
|
|
#endif
|
233 |
|
|
|
234 |
|
|
|
235 |
|
|
#define TPQIC02_NAME "tpqic02"
|
236 |
|
|
|
237 |
|
|
/* Linux outb() commands have (value,port) as parameters.
|
238 |
|
|
* One might expect (port,value) instead, so beware!
|
239 |
|
|
*/
|
240 |
|
|
|
241 |
|
|
#ifdef CONFIG_QIC02_DYNCONF
|
242 |
|
|
/* This holds the dynamic configuration info for the interface
|
243 |
|
|
* card+drive info if runtime configuration has been selected.
|
244 |
|
|
*/
|
245 |
|
|
struct mtconfiginfo qic02_tape_dynconf = { 0, }; /* user settable */
|
246 |
|
|
struct qic02_ccb qic02_tape_ccb = { 0, }; /* private stuff */
|
247 |
|
|
|
248 |
|
|
#else
|
249 |
|
|
|
250 |
|
|
unsigned long qic02_tape_debug;
|
251 |
|
|
|
252 |
|
|
# if ((QIC02_TAPE_IFC!=WANGTEK) && (QIC02_TAPE_IFC!=ARCHIVE) && (QIC02_TAPE_IFC!=MOUNTAIN))
|
253 |
|
|
# error No valid interface card specified
|
254 |
|
|
# endif
|
255 |
|
|
#endif
|
256 |
|
|
|
257 |
|
|
static volatile int ctlbits = 0; /* control reg bits for tape interface */
|
258 |
|
|
|
259 |
|
|
static struct wait_queue *qic02_tape_transfer = NULL; /* sync rw with interrupts */
|
260 |
|
|
|
261 |
|
|
static volatile struct mtget ioctl_status; /* current generic status */
|
262 |
|
|
|
263 |
|
|
static volatile struct tpstatus tperror; /* last drive status */
|
264 |
|
|
|
265 |
|
|
static char rcs_revision[] = "$Revision: 1.1.1.1 $";
|
266 |
|
|
static char rcs_date[] = "$Date: 2001-09-10 07:44:17 $";
|
267 |
|
|
|
268 |
|
|
/* Flag bits for status and outstanding requests.
|
269 |
|
|
* (Could all be put in one bit-field-struct.)
|
270 |
|
|
* Some variables need `volatile' because they may be modified
|
271 |
|
|
* by an interrupt.
|
272 |
|
|
*/
|
273 |
|
|
static volatile flag status_dead = YES; /* device is legally dead until proven alive */
|
274 |
|
|
static flag status_zombie = YES; /* it's `zombie' until irq/dma allocated */
|
275 |
|
|
|
276 |
|
|
static volatile flag status_bytes_wr = NO; /* write FM at close or not */
|
277 |
|
|
static volatile flag status_bytes_rd = NO; /* (rd|wr) used for rewinding */
|
278 |
|
|
|
279 |
|
|
static volatile unsigned long status_cmd_pending = 0; /* cmd in progress */
|
280 |
|
|
static volatile flag status_expect_int = NO; /* ready for interrupts */
|
281 |
|
|
static volatile flag status_timer_on = NO; /* using time-out */
|
282 |
|
|
static volatile int status_error = 0; /* int handler may detect error */
|
283 |
|
|
static volatile flag status_eof_detected = NO; /* end of file */
|
284 |
|
|
static volatile flag status_eom_detected = NO; /* end of recorded media */
|
285 |
|
|
static volatile flag status_eot_detected = NO; /* end of tape */
|
286 |
|
|
static volatile flag doing_read = NO;
|
287 |
|
|
static volatile flag doing_write = NO;
|
288 |
|
|
|
289 |
|
|
static volatile unsigned long dma_bytes_todo;
|
290 |
|
|
static volatile unsigned long dma_bytes_done;
|
291 |
|
|
static volatile unsigned dma_mode = 0; /* !=0 also means DMA in use */
|
292 |
|
|
static flag need_rewind = YES;
|
293 |
|
|
|
294 |
|
|
static kdev_t current_tape_dev;
|
295 |
|
|
static int extra_blocks_left = BLOCKS_BEYOND_EW;
|
296 |
|
|
|
297 |
|
|
|
298 |
|
|
/* return_*_eof:
|
299 |
|
|
* NO: not at EOF,
|
300 |
|
|
* YES: tell app EOF was reached (return 0).
|
301 |
|
|
*
|
302 |
|
|
* return_*_eof==YES && reported_*_eof==NO ==>
|
303 |
|
|
* return current buffer, next time(s) return EOF.
|
304 |
|
|
*
|
305 |
|
|
* return_*_eof==YES && reported_*_eof==YES ==>
|
306 |
|
|
* at EOF and application knows it, so we can
|
307 |
|
|
* move on to the next file.
|
308 |
|
|
*
|
309 |
|
|
*/
|
310 |
|
|
static flag return_read_eof = NO; /* set to signal app EOF was reached */
|
311 |
|
|
static flag return_write_eof = NO;
|
312 |
|
|
static flag reported_read_eof = NO; /* set when we've done that */
|
313 |
|
|
static flag reported_write_eof = NO;
|
314 |
|
|
|
315 |
|
|
|
316 |
|
|
/* This is for doing `mt seek <blocknr>' */
|
317 |
|
|
static char seek_addr_buf[AR_SEEK_BUF_SIZE];
|
318 |
|
|
|
319 |
|
|
|
320 |
|
|
/* In write mode, we have to write a File Mark after the last block written,
|
321 |
|
|
* when the tape device is closed. Tape repositioning and reading in write
|
322 |
|
|
* mode is allowed as long as no actual writing has been done. After writing
|
323 |
|
|
* the File Mark, repositioning and reading are allowed again.
|
324 |
|
|
*/
|
325 |
|
|
static int mode_access; /* access mode: READ or WRITE */
|
326 |
|
|
|
327 |
|
|
|
328 |
|
|
/* This is the actual kernel buffer where the interrupt routines read
|
329 |
|
|
* from/write to. It is needed because the DMA channels 1 and 3 cannot
|
330 |
|
|
* always access the user buffers. [The kernel buffer must reside in the
|
331 |
|
|
* lower 16MBytes of system memory because of the DMA controller.]
|
332 |
|
|
* The user must ensure that a large enough buffer is passed to the
|
333 |
|
|
* kernel, in order to reduce tape repositioning.
|
334 |
|
|
*
|
335 |
|
|
* The buffer is 512 bytes larger than expected, because I want to align it
|
336 |
|
|
* at 512 bytes, to prevent problems with 64k boundaries.
|
337 |
|
|
*/
|
338 |
|
|
|
339 |
|
|
static volatile char qic02_tape_buf[TPQBUF_SIZE+TAPE_BLKSIZE];
|
340 |
|
|
/* A really good compiler would be able to align this at 512 bytes... :-( */
|
341 |
|
|
|
342 |
|
|
static unsigned long buffaddr; /* aligned physical address of buffer */
|
343 |
|
|
|
344 |
|
|
|
345 |
|
|
/* This translates minor numbers to the corresponding recording format: */
|
346 |
|
|
static const char *format_names[] = {
|
347 |
|
|
"not set", /* for dumb drives unable to handle format selection */
|
348 |
|
|
"11", /* extinct */
|
349 |
|
|
"24",
|
350 |
|
|
"120",
|
351 |
|
|
"150",
|
352 |
|
|
"300", /* untested. */
|
353 |
|
|
"600" /* untested. */
|
354 |
|
|
};
|
355 |
|
|
|
356 |
|
|
|
357 |
|
|
/* `exception_list' is needed for exception status reporting.
|
358 |
|
|
* Exceptions 1..14 are defined by QIC-02 rev F.
|
359 |
|
|
* The drive status is matched sequentially to each entry,
|
360 |
|
|
* ignoring irrelevant bits, until a match is found. If no
|
361 |
|
|
* match is found, exception number 0 is used. (That should of
|
362 |
|
|
* course never happen...) The original table was based on the
|
363 |
|
|
* "Exception Status Summary" in QIC-02 rev F, but some changes
|
364 |
|
|
* were required to make it work with real-world drives.
|
365 |
|
|
*
|
366 |
|
|
* Exception 2 (CNI) is changed to also cover status 0x00e0 (mask USL),
|
367 |
|
|
* Exception 4 (EOM) is changed to also cover status 0x8288 (mask EOR),
|
368 |
|
|
* Exception 11 (FIL) is changed to also cover status 0x0089 (mask EOM).
|
369 |
|
|
* Exception 15 (EOR) is added for seek-to-end-of-data (catch EOR),
|
370 |
|
|
* Exception 16 (BOM) is added for beginning-of-media (catch BOM).
|
371 |
|
|
*
|
372 |
|
|
* Had to swap EXC_NDRV and EXC_NCART to ensure that extended EXC_NCART
|
373 |
|
|
* (because of the incorrect Wangtek status code) doesn't catch the
|
374 |
|
|
* EXC_NDRV first.
|
375 |
|
|
*/
|
376 |
|
|
static struct exception_list_type {
|
377 |
|
|
unsigned short mask, code;
|
378 |
|
|
const char *msg;
|
379 |
|
|
/* EXC_nr attribute should match with tpqic02.h */
|
380 |
|
|
} exception_list[] = {
|
381 |
|
|
{0, 0,
|
382 |
|
|
"Unknown exception status code", /* extra: 0 */},
|
383 |
|
|
{~(0), TP_ST0|TP_CNI|TP_USL|TP_WRP,
|
384 |
|
|
"Drive not online" /* 1 */},
|
385 |
|
|
/* Drive presence goes before cartridge presence. */
|
386 |
|
|
{~(TP_WRP|TP_USL), TP_ST0|TP_CNI,
|
387 |
|
|
/* My Wangtek 5150EQ sometimes reports a status code
|
388 |
|
|
* of 0x00e0, which is not a valid exception code, but
|
389 |
|
|
* I think it should be recognized as "NO CARTRIDGE".
|
390 |
|
|
*/
|
391 |
|
|
"Cartridge not in place" /* 2 */},
|
392 |
|
|
{(unsigned short) ~(TP_ST1|TP_BOM), (TP_ST0|TP_WRP),
|
393 |
|
|
"Write protected cartridge" /* 3 */},
|
394 |
|
|
{(unsigned short) ~(TP_ST1|TP_EOR), (TP_ST0|TP_EOM),
|
395 |
|
|
"End of media" /* 4 */},
|
396 |
|
|
{~TP_WRP, TP_ST0|TP_UDA| TP_ST1|TP_BOM,
|
397 |
|
|
"Read or Write abort. Rewind tape." /* 5 */},
|
398 |
|
|
{~TP_WRP, TP_ST0|TP_UDA,
|
399 |
|
|
"Read error. Bad block transferred." /* 6 */},
|
400 |
|
|
{~TP_WRP, TP_ST0|TP_UDA|TP_BNL,
|
401 |
|
|
"Read error. Filler block transferred." /* 7 */},
|
402 |
|
|
{~TP_WRP, TP_ST0|TP_UDA|TP_BNL |TP_ST1|TP_NDT,
|
403 |
|
|
"Read error. No data detected." /* 8 */},
|
404 |
|
|
{~TP_WRP, TP_ST0|TP_EOM|TP_UDA|TP_BNL |TP_ST1|TP_NDT,
|
405 |
|
|
"Read error. No data detected. EOM." /* 9 */},
|
406 |
|
|
{~(TP_WRP|TP_MBD|TP_PAR|TP_EOR), TP_ST0|TP_UDA|TP_BNL |TP_ST1|TP_NDT|TP_BOM,
|
407 |
|
|
"Read error. No data detected. BOM." /* 10 */},
|
408 |
|
|
{~(TP_WRP|TP_EOM), TP_ST0|TP_FIL,
|
409 |
|
|
/* Status 0x0089 (EOM & FM) is viewed as an FM,
|
410 |
|
|
* because it can only happen during a read.
|
411 |
|
|
* EOM is checked separately for an FM condition.
|
412 |
|
|
*/
|
413 |
|
|
"File mark detected" /* 11 */},
|
414 |
|
|
{~(TP_ST0|TP_CNI|TP_USL|TP_WRP|TP_BOM), TP_ST1|TP_ILL,
|
415 |
|
|
"Illegal command" /* 12 */},
|
416 |
|
|
{~(TP_ST0|TP_CNI|TP_USL|TP_WRP|TP_BOM), TP_ST1|TP_POR,
|
417 |
|
|
"Reset occurred" /* 13 */},
|
418 |
|
|
{~TP_WRP, TP_ST0|TP_FIL|TP_MBD, /* NOTE: ST1 not set! */
|
419 |
|
|
"Marginal block detected" /* 14 */},
|
420 |
|
|
{~(TP_ST0|TP_WRP|TP_EOM|TP_UDA|TP_BNL|TP_FIL |TP_NDT), TP_ST1|TP_EOR,
|
421 |
|
|
/********** Is the extra TP_NDT really needed Eddy? **********/
|
422 |
|
|
"End of recorded media" /* extra: 15 */},
|
423 |
|
|
/* 15 is returned when SEEKEOD completes successfully */
|
424 |
|
|
{~(TP_WRP|TP_ST0), TP_ST1|TP_BOM,
|
425 |
|
|
"Beginning of media" /* extra: 16 */}
|
426 |
|
|
};
|
427 |
|
|
#define NR_OF_EXC (sizeof(exception_list)/sizeof(struct exception_list_type))
|
428 |
|
|
|
429 |
|
|
|
430 |
|
|
|
431 |
|
|
static void tpqputs(unsigned long flags, const char *s)
|
432 |
|
|
{
|
433 |
|
|
if ((flags & TPQD_ALWAYS) || (flags & QIC02_TAPE_DEBUG))
|
434 |
|
|
printk(TPQIC02_NAME ": %s\n", s);
|
435 |
|
|
} /* tpqputs */
|
436 |
|
|
|
437 |
|
|
|
438 |
|
|
|
439 |
|
|
|
440 |
|
|
/* Perform byte order swapping for a 16-bit word.
|
441 |
|
|
*
|
442 |
|
|
* [FIXME] This should probably be in include/asm/
|
443 |
|
|
* ([FIXME] i486 can do this faster)
|
444 |
|
|
*/
|
445 |
|
|
static inline void byte_swap_w(volatile unsigned short * w)
|
446 |
|
|
{
|
447 |
|
|
int t = *w;
|
448 |
|
|
|
449 |
|
|
*w = (t>>8) | ((t & 0xff)<<8);
|
450 |
|
|
}
|
451 |
|
|
|
452 |
|
|
|
453 |
|
|
|
454 |
|
|
/* Init control register bits on interface card.
|
455 |
|
|
* For Archive, interrupts must be enabled explicitly.
|
456 |
|
|
* Wangtek interface card requires ONLINE to be set, Archive SC402/SC499R
|
457 |
|
|
* cards keep it active all the time.
|
458 |
|
|
*/
|
459 |
|
|
static void ifc_init(void)
|
460 |
|
|
{
|
461 |
|
|
if (QIC02_TAPE_IFC == WANGTEK) /* || (QIC02_TAPE_IFC == EVEREX) */ {
|
462 |
|
|
ctlbits = WT_CTL_ONLINE; /* online */
|
463 |
|
|
outb_p(ctlbits, QIC02_CTL_PORT);
|
464 |
|
|
|
465 |
|
|
} else if (QIC02_TAPE_IFC == ARCHIVE) {
|
466 |
|
|
ctlbits = 0; /* no interrupts yet */
|
467 |
|
|
outb_p(ctlbits, QIC02_CTL_PORT);
|
468 |
|
|
outb_p(0, AR_RESET_DMA_PORT); /* dummy write to reset DMA */
|
469 |
|
|
|
470 |
|
|
} else /* MOUNTAIN */ {
|
471 |
|
|
ctlbits = MTN_CTL_ONLINE; /* online, and logic enabled */
|
472 |
|
|
outb_p(ctlbits, QIC02_CTL_PORT);
|
473 |
|
|
}
|
474 |
|
|
} /* ifc_init */
|
475 |
|
|
|
476 |
|
|
|
477 |
|
|
static void report_exception(unsigned n)
|
478 |
|
|
{
|
479 |
|
|
if (n >= NR_OF_EXC) { tpqputs(TPQD_ALWAYS, "Oops -- report_exception"); n = 0; }
|
480 |
|
|
if (TPQDBG(SENSE_TEXT) || n==0)
|
481 |
|
|
printk(TPQIC02_NAME ": sense: %s\n", exception_list[n].msg);
|
482 |
|
|
} /* report_exception */
|
483 |
|
|
|
484 |
|
|
|
485 |
|
|
/* Try to map the drive-exception bits `s' to a predefined "exception number",
|
486 |
|
|
* by comparing the significant exception bits for each entry in the
|
487 |
|
|
* exception table (`exception_list[]').
|
488 |
|
|
* It is assumed that s!=0.
|
489 |
|
|
*/
|
490 |
|
|
static int decode_exception_nr(unsigned s)
|
491 |
|
|
{
|
492 |
|
|
int i;
|
493 |
|
|
|
494 |
|
|
for (i=1; i<NR_OF_EXC; i++) {
|
495 |
|
|
if ((s & exception_list[i].mask)==exception_list[i].code)
|
496 |
|
|
return i;
|
497 |
|
|
}
|
498 |
|
|
printk(TPQIC02_NAME ": decode_exception_nr: exception(%x) not recognized\n", s);
|
499 |
|
|
return 0;
|
500 |
|
|
} /* decode_exception_nr */
|
501 |
|
|
|
502 |
|
|
|
503 |
|
|
#ifdef OBSOLETE
|
504 |
|
|
/* There are exactly 14 possible exceptions, as defined in QIC-02 rev F.
|
505 |
|
|
* Some are FATAL, some aren't. Currently all exceptions are treated as fatal.
|
506 |
|
|
* Especially 6 and 14 should not abort the transfer. RSN...
|
507 |
|
|
* Should probably let sense() figure out the exception number using the code
|
508 |
|
|
* below, and just report the error based on the number here, returning a code
|
509 |
|
|
* for FATAL/CONTINUABLE.
|
510 |
|
|
*/
|
511 |
|
|
static void report_error(int s)
|
512 |
|
|
{
|
513 |
|
|
short n = -1;
|
514 |
|
|
|
515 |
|
|
if (s & TP_ST1) {
|
516 |
|
|
if (s & TP_ILL) /* 12: Illegal command. FATAL */
|
517 |
|
|
n = 12;
|
518 |
|
|
if (s & TP_POR) /* 13: Reset occurred. FATAL */
|
519 |
|
|
n = 13;
|
520 |
|
|
}
|
521 |
|
|
else if (s & TP_ST0) {
|
522 |
|
|
if (s & TP_EOR) { /* extra: 15: End of Recorded Media. CONTINUABLE */
|
523 |
|
|
n = 15;
|
524 |
|
|
/********** should set flag here **********/
|
525 |
|
|
}
|
526 |
|
|
else if (s & TP_EOM) /* 4: End Of Media. CONTINUABLE */
|
527 |
|
|
n = 4;
|
528 |
|
|
else if (s & TP_USL) /* 2: Drive not online. FATAL */
|
529 |
|
|
n = 2;
|
530 |
|
|
else if (s & TP_CNI) { /* 1: Cartridge not in place. FATAL */
|
531 |
|
|
n = 1;
|
532 |
|
|
need_rewind = YES;
|
533 |
|
|
status_eof_detected = NO;
|
534 |
|
|
status_eom_detected = NO;
|
535 |
|
|
}
|
536 |
|
|
else if (s & TP_UDA) {
|
537 |
|
|
if (s & TP_BNL) {
|
538 |
|
|
if (s & TP_NDT) {
|
539 |
|
|
if (s & TP_BOM) /* 9: Read error. No data detected & EOM. CONTINUABLE */
|
540 |
|
|
n = 9;
|
541 |
|
|
else if (s & TP_EOM) /* 10: Read error. No data detected & BOM. CONTINUABLE */
|
542 |
|
|
n = 10;
|
543 |
|
|
else /* 8: Read error. No data detected. CONTINUABLE */
|
544 |
|
|
n = 8;
|
545 |
|
|
} else { /* 7: Read error. Cannot recover block, filler substituted. CONTINUABLE */
|
546 |
|
|
tpqputs(TPQD_ALWAYS, "[Bad block -- filler data transferred.]");
|
547 |
|
|
n = 7;
|
548 |
|
|
}
|
549 |
|
|
}
|
550 |
|
|
else {
|
551 |
|
|
if (s & TP_EOM) /* 5: Read or Write error. Rewind tape. FATAL */
|
552 |
|
|
n = 5;
|
553 |
|
|
else { /* 6: Read error. Bad block transferred. CONTINUABLE */
|
554 |
|
|
/* block is bad, but transfer may continue.
|
555 |
|
|
* This is why some people prefer not to
|
556 |
|
|
* use compression on backups...
|
557 |
|
|
*/
|
558 |
|
|
tpqputs(TPQD_ALWAYS, "[CRC failed!]");
|
559 |
|
|
n = 6;
|
560 |
|
|
}
|
561 |
|
|
}
|
562 |
|
|
}
|
563 |
|
|
else if (s & TP_FIL) {
|
564 |
|
|
if (s & TP_MBD) { /* 14: Marginal block detected. CONTINUABLE */
|
565 |
|
|
tpqputs(TPQD_ALWAYS, "[Marginal block]");
|
566 |
|
|
n = 14;
|
567 |
|
|
} else /* 11: File mark detected. CONTINUABLE */
|
568 |
|
|
n = 11;
|
569 |
|
|
}
|
570 |
|
|
else if (s & TP_WRP) /* 3: Write protected cartridge. FATAL */
|
571 |
|
|
n = 3;
|
572 |
|
|
}
|
573 |
|
|
if (n >= 0)
|
574 |
|
|
sensemsg(n);
|
575 |
|
|
} /* report_error */
|
576 |
|
|
#endif
|
577 |
|
|
|
578 |
|
|
|
579 |
|
|
/* Perform appropriate action for certain exceptions.
|
580 |
|
|
* should return a value to indicate stop/continue (in case of bad blocks)
|
581 |
|
|
*/
|
582 |
|
|
static void handle_exception(int exnr, int exbits)
|
583 |
|
|
{
|
584 |
|
|
if (exnr==EXC_NCART) {
|
585 |
|
|
/* Cartridge was changed. Redo sense().
|
586 |
|
|
* EXC_NCART should be handled in open().
|
587 |
|
|
* It is not permitted to remove the tape while
|
588 |
|
|
* the tape driver has open files.
|
589 |
|
|
*/
|
590 |
|
|
need_rewind = YES;
|
591 |
|
|
status_eof_detected = NO;
|
592 |
|
|
status_eom_detected = NO;
|
593 |
|
|
}
|
594 |
|
|
else if (exnr==EXC_XFILLER)
|
595 |
|
|
tpqputs(TPQD_ALWAYS, "[Bad block -- filler data transferred.]");
|
596 |
|
|
else if (exnr==EXC_XBAD)
|
597 |
|
|
tpqputs(TPQD_ALWAYS, "[CRC failed!]");
|
598 |
|
|
else if (exnr==EXC_MARGINAL) {
|
599 |
|
|
/* A marginal block behaves much like a FM.
|
600 |
|
|
* User may continue reading, if desired.
|
601 |
|
|
*/
|
602 |
|
|
tpqputs(TPQD_ALWAYS, "[Marginal block]");
|
603 |
|
|
doing_read = NO;
|
604 |
|
|
} else if (exnr==EXC_FM)
|
605 |
|
|
doing_read = NO;
|
606 |
|
|
} /* handle_exception */
|
607 |
|
|
|
608 |
|
|
|
609 |
|
|
static inline int is_exception(void)
|
610 |
|
|
{
|
611 |
|
|
return (inb(QIC02_STAT_PORT) & QIC02_STAT_EXCEPTION) == 0;
|
612 |
|
|
} /* is_exception */
|
613 |
|
|
|
614 |
|
|
|
615 |
|
|
/* Reset the tape drive and controller.
|
616 |
|
|
* When reset fails, it marks the drive as dead and all
|
617 |
|
|
* requests (except reset) are to be ignored (ENXIO).
|
618 |
|
|
*/
|
619 |
|
|
static int tape_reset(int verbose)
|
620 |
|
|
{
|
621 |
|
|
ifc_init(); /* reset interface card */
|
622 |
|
|
|
623 |
|
|
/* assert reset */
|
624 |
|
|
if (QIC02_TAPE_IFC == MOUNTAIN)
|
625 |
|
|
outb_p(ctlbits & ~MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);
|
626 |
|
|
else /* WANGTEK, ARCHIVE */
|
627 |
|
|
outb_p(ctlbits | QIC02_CTL_RESET, QIC02_CTL_PORT);
|
628 |
|
|
|
629 |
|
|
/* Next, we need to wait >=25 usec. */
|
630 |
|
|
udelay(30);
|
631 |
|
|
|
632 |
|
|
/* after reset, we will be at BOT (modulo an automatic rewind) */
|
633 |
|
|
status_eof_detected = NO;
|
634 |
|
|
status_eom_detected = NO;
|
635 |
|
|
status_cmd_pending = 0;
|
636 |
|
|
need_rewind = YES;
|
637 |
|
|
doing_read = doing_write = NO;
|
638 |
|
|
ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
|
639 |
|
|
|
640 |
|
|
/* de-assert reset */
|
641 |
|
|
if (QIC02_TAPE_IFC == MOUNTAIN)
|
642 |
|
|
outb_p(ctlbits | MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);
|
643 |
|
|
else
|
644 |
|
|
outb_p(ctlbits & ~QIC02_CTL_RESET, QIC02_CTL_PORT);
|
645 |
|
|
|
646 |
|
|
/* KLUDGE FOR G++ BUG */
|
647 |
|
|
{ int stat = inb_p(QIC02_STAT_PORT);
|
648 |
|
|
status_dead = ((stat & QIC02_STAT_RESETMASK) != QIC02_STAT_RESETVAL); }
|
649 |
|
|
/* if successful, inb(STAT) returned RESETVAL */
|
650 |
|
|
if (status_dead == YES)
|
651 |
|
|
printk(TPQIC02_NAME ": reset failed!\n");
|
652 |
|
|
else if (verbose)
|
653 |
|
|
printk(TPQIC02_NAME ": reset successful\n");
|
654 |
|
|
|
655 |
|
|
return (status_dead == YES)? TE_DEAD : TE_OK;
|
656 |
|
|
} /* tape_reset */
|
657 |
|
|
|
658 |
|
|
|
659 |
|
|
|
660 |
|
|
/* Notify tape drive of a new command. It only waits for the
|
661 |
|
|
* command to be accepted, not for the actual command to complete.
|
662 |
|
|
*
|
663 |
|
|
* Before calling this routine, QIC02_CMD_PORT must have been loaded
|
664 |
|
|
* with the command to be executed.
|
665 |
|
|
* After this routine, the exception bit must be checked.
|
666 |
|
|
* This routine is also used by rdstatus(), so in that case, any exception
|
667 |
|
|
* must be ignored (`ignore_ex' flag).
|
668 |
|
|
*/
|
669 |
|
|
static int notify_cmd(char cmd, short ignore_ex)
|
670 |
|
|
{
|
671 |
|
|
int i;
|
672 |
|
|
|
673 |
|
|
outb_p(cmd, QIC02_CMD_PORT); /* output the command */
|
674 |
|
|
|
675 |
|
|
/* wait 1 usec before asserting /REQUEST */
|
676 |
|
|
udelay(1);
|
677 |
|
|
|
678 |
|
|
if ((!ignore_ex) && is_exception()) {
|
679 |
|
|
tpqputs(TPQD_ALWAYS, "*** exception detected in notify_cmd");
|
680 |
|
|
/** force a reset here **/
|
681 |
|
|
if (tape_reset(1)==TE_DEAD)
|
682 |
|
|
return TE_DEAD;
|
683 |
|
|
if (is_exception()) {
|
684 |
|
|
tpqputs(TPQD_ALWAYS, "exception persists after reset.");
|
685 |
|
|
tpqputs(TPQD_ALWAYS, " ^ exception ignored.");
|
686 |
|
|
}
|
687 |
|
|
}
|
688 |
|
|
|
689 |
|
|
outb_p(ctlbits | QIC02_CTL_REQUEST, QIC02_CTL_PORT); /* set request bit */
|
690 |
|
|
i = TAPE_NOTIFY_TIMEOUT;
|
691 |
|
|
/* The specs say this takes about 500 usec, but there is no upper limit!
|
692 |
|
|
* If the drive were busy retensioning or something like that,
|
693 |
|
|
* it could be *much* longer!
|
694 |
|
|
*/
|
695 |
|
|
while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) && (--i>0))
|
696 |
|
|
/*skip*/; /* wait for ready */
|
697 |
|
|
if (i==0) {
|
698 |
|
|
tpqputs(TPQD_ALWAYS, "timed out waiting for ready in notify_cmd");
|
699 |
|
|
status_dead = YES;
|
700 |
|
|
return TE_TIM;
|
701 |
|
|
}
|
702 |
|
|
|
703 |
|
|
outb_p(ctlbits & ~QIC02_CTL_REQUEST, QIC02_CTL_PORT); /* reset request bit */
|
704 |
|
|
i = TAPE_NOTIFY_TIMEOUT;
|
705 |
|
|
/* according to the specs this one should never time-out */
|
706 |
|
|
while (((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0) && (--i>0))
|
707 |
|
|
/*skip*/; /* wait for not ready */
|
708 |
|
|
if (i==0) {
|
709 |
|
|
tpqputs(TPQD_ALWAYS, "timed out waiting for !ready in notify_cmd");
|
710 |
|
|
status_dead = YES;
|
711 |
|
|
return TE_TIM;
|
712 |
|
|
}
|
713 |
|
|
/* command accepted */
|
714 |
|
|
return TE_OK;
|
715 |
|
|
} /* notify_cmd */
|
716 |
|
|
|
717 |
|
|
|
718 |
|
|
|
719 |
|
|
/* Wait for a command to complete, with timeout */
|
720 |
|
|
static int wait_for_ready(time_t timeout)
|
721 |
|
|
{
|
722 |
|
|
int stat;
|
723 |
|
|
time_t spin_t;
|
724 |
|
|
|
725 |
|
|
/* Wait for ready or exception, without driving the loadavg up too much.
|
726 |
|
|
* In most cases, the tape drive already has READY asserted,
|
727 |
|
|
* so optimize for that case.
|
728 |
|
|
*
|
729 |
|
|
* First, busy wait a few usec:
|
730 |
|
|
*/
|
731 |
|
|
spin_t = 50;
|
732 |
|
|
while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (--spin_t>0))
|
733 |
|
|
/*SKIP*/;
|
734 |
|
|
if ((stat & QIC02_STAT_READY) == 0)
|
735 |
|
|
return TE_OK; /* covers 99.99% of all calls */
|
736 |
|
|
|
737 |
|
|
/* Then use schedule() a few times */
|
738 |
|
|
spin_t = 3; /* max 0.03 sec busy waiting */
|
739 |
|
|
if (spin_t > timeout)
|
740 |
|
|
spin_t = timeout;
|
741 |
|
|
timeout -= spin_t;
|
742 |
|
|
spin_t += jiffies;
|
743 |
|
|
|
744 |
|
|
while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (jiffies<spin_t))
|
745 |
|
|
schedule(); /* don't waste all the CPU time */
|
746 |
|
|
if ((stat & QIC02_STAT_READY) == 0)
|
747 |
|
|
return TE_OK;
|
748 |
|
|
|
749 |
|
|
/* If we reach this point, we probably need to wait much longer, or
|
750 |
|
|
* an exception occurred. Either case is not very time-critical.
|
751 |
|
|
* Check the status port only a few times every second.
|
752 |
|
|
* A interval of less than 0.10 sec will not be noticed by the user,
|
753 |
|
|
* more than 0.40 sec may give noticeable delays.
|
754 |
|
|
*/
|
755 |
|
|
spin_t += timeout;
|
756 |
|
|
TPQDEB({printk("wait_for_ready: additional timeout: %d\n", spin_t);})
|
757 |
|
|
|
758 |
|
|
/* not ready and no exception && timeout not expired yet */
|
759 |
|
|
while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (jiffies<spin_t)) {
|
760 |
|
|
/* be `nice` to other processes on long operations... */
|
761 |
|
|
current->timeout = jiffies + 3*HZ/10; /* nap 0.30 sec between checks, */
|
762 |
|
|
current->state = TASK_INTERRUPTIBLE;
|
763 |
|
|
schedule(); /* but could be woken up earlier by signals... */
|
764 |
|
|
}
|
765 |
|
|
|
766 |
|
|
/* don't use jiffies for this test because it may have changed by now */
|
767 |
|
|
if ((stat & QIC02_STAT_MASK) == QIC02_STAT_MASK) {
|
768 |
|
|
tpqputs(TPQD_ALWAYS, "wait_for_ready() timed out");
|
769 |
|
|
return TE_TIM;
|
770 |
|
|
}
|
771 |
|
|
|
772 |
|
|
if ((stat & QIC02_STAT_EXCEPTION) == 0) {
|
773 |
|
|
tpqputs(TPQD_ALWAYS, "exception detected after waiting_for_ready");
|
774 |
|
|
return TE_EX;
|
775 |
|
|
} else {
|
776 |
|
|
return TE_OK;
|
777 |
|
|
}
|
778 |
|
|
} /* wait_for_ready */
|
779 |
|
|
|
780 |
|
|
|
781 |
|
|
|
782 |
|
|
/* Send some data to the drive */
|
783 |
|
|
static int send_qic02_data(char sb[], unsigned size, int ignore_ex)
|
784 |
|
|
{
|
785 |
|
|
int i, stat;
|
786 |
|
|
|
787 |
|
|
for (i=0; i<size; i++) {
|
788 |
|
|
|
789 |
|
|
stat = wait_for_ready(TIM_S);
|
790 |
|
|
if (stat != TE_OK)
|
791 |
|
|
return stat;
|
792 |
|
|
|
793 |
|
|
stat = notify_cmd(sb[i], ignore_ex);
|
794 |
|
|
if (stat != TE_OK)
|
795 |
|
|
return stat;
|
796 |
|
|
}
|
797 |
|
|
return TE_OK;
|
798 |
|
|
|
799 |
|
|
} /* send_qic02_data */
|
800 |
|
|
|
801 |
|
|
|
802 |
|
|
/* Send a QIC-02 command (`cmd') to the tape drive, with
|
803 |
|
|
* a time-out (`timeout').
|
804 |
|
|
* This one is also used by tp_sense(), so we must have
|
805 |
|
|
* a flag to disable exception checking (`ignore_ex').
|
806 |
|
|
*
|
807 |
|
|
* On entry, the controller is supposed to be READY.
|
808 |
|
|
*/
|
809 |
|
|
static int send_qic02_cmd(int cmd, time_t timeout, int ignore_ex)
|
810 |
|
|
{
|
811 |
|
|
int stat;
|
812 |
|
|
|
813 |
|
|
stat = inb_p(QIC02_STAT_PORT);
|
814 |
|
|
if ((stat & QIC02_STAT_EXCEPTION) == 0) { /* if exception */
|
815 |
|
|
tpqputs(TPQD_ALWAYS, "send_qic02_cmd: Exception!");
|
816 |
|
|
return TE_EX;
|
817 |
|
|
}
|
818 |
|
|
if (stat & QIC02_STAT_READY) { /* if not ready */
|
819 |
|
|
tpqputs(TPQD_ALWAYS, "send_qic02_cmd: not Ready!");
|
820 |
|
|
return TE_ERR;
|
821 |
|
|
}
|
822 |
|
|
|
823 |
|
|
/* assert(ready & !exception) */
|
824 |
|
|
|
825 |
|
|
/* Remember current command for later re-use with dma transfers.
|
826 |
|
|
* (For reading/writing multiple blocks.)
|
827 |
|
|
*/
|
828 |
|
|
status_cmd_pending = cmd;
|
829 |
|
|
|
830 |
|
|
stat = notify_cmd(cmd, ignore_ex); /* tell drive new command was loaded, */
|
831 |
|
|
/* inherit exception check. */
|
832 |
|
|
if (TP_HAVE_SEEK && (cmd == AR_QCMDV_SEEK_BLK)) {
|
833 |
|
|
/* This one needs to send 3 more bytes, MSB first */
|
834 |
|
|
stat = send_qic02_data(seek_addr_buf, sizeof(seek_addr_buf), ignore_ex);
|
835 |
|
|
}
|
836 |
|
|
|
837 |
|
|
if (stat != TE_OK) {
|
838 |
|
|
tpqputs(TPQD_ALWAYS, "send_qic02_cmd failed");
|
839 |
|
|
}
|
840 |
|
|
return stat;
|
841 |
|
|
} /* send_qic02_cmd */
|
842 |
|
|
|
843 |
|
|
|
844 |
|
|
|
845 |
|
|
/* Get drive status. Assume drive is ready or has exception set.
|
846 |
|
|
* (or will be in <1000 usec.)
|
847 |
|
|
* Extra parameters added because of 'Read Extended Status 3' command.
|
848 |
|
|
*/
|
849 |
|
|
static int rdstatus(char *stp, unsigned size, char qcmd)
|
850 |
|
|
{
|
851 |
|
|
int s, n;
|
852 |
|
|
char *q = stp;
|
853 |
|
|
|
854 |
|
|
/* Try to busy-wait a few (700) usec, after that de-schedule.
|
855 |
|
|
*
|
856 |
|
|
* The problem is, if we don't de-schedule, performance will
|
857 |
|
|
* drop to zero when the drive is not responding and if we
|
858 |
|
|
* de-schedule immediately, we waste a lot of time because a
|
859 |
|
|
* task switch is much longer than we usually have to wait here.
|
860 |
|
|
*/
|
861 |
|
|
n = 1000; /* 500 is not enough on a 486/33 */
|
862 |
|
|
while ((n>0) && ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK))
|
863 |
|
|
n--; /* wait for ready or exception or timeout */
|
864 |
|
|
if (n==0) {
|
865 |
|
|
/* n (above) should be chosen such that on your machine
|
866 |
|
|
* you rarely ever see the message below, and it should
|
867 |
|
|
* be small enough to give reasonable response time.]
|
868 |
|
|
*/
|
869 |
|
|
tpqputs(TPQD_ALWAYS, "waiting looong in rdstatus() -- drive dead?");
|
870 |
|
|
while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK)
|
871 |
|
|
schedule();
|
872 |
|
|
tpqputs(TPQD_ALWAYS, "finished waiting in rdstatus()");
|
873 |
|
|
}
|
874 |
|
|
|
875 |
|
|
(void) notify_cmd(qcmd, 1); /* send read status command */
|
876 |
|
|
/* ignore return code -- should always be ok, STAT may contain
|
877 |
|
|
* exception flag from previous exception which we are trying to clear.
|
878 |
|
|
*/
|
879 |
|
|
|
880 |
|
|
if (TP_DIAGS(current_tape_dev))
|
881 |
|
|
printk(TPQIC02_NAME ": reading status bytes: ");
|
882 |
|
|
|
883 |
|
|
for (q=stp; q<stp+size; q++)
|
884 |
|
|
{
|
885 |
|
|
do s = inb_p(QIC02_STAT_PORT);
|
886 |
|
|
while ((s & QIC02_STAT_MASK) == QIC02_STAT_MASK); /* wait for ready or exception */
|
887 |
|
|
|
888 |
|
|
if ((s & QIC02_STAT_EXCEPTION) == 0) { /* if exception */
|
889 |
|
|
tpqputs(TPQD_ALWAYS, "rdstatus: exception error");
|
890 |
|
|
ioctl_status.mt_erreg = 0; /* dunno... */
|
891 |
|
|
return TE_NS; /* error, shouldn't happen... */
|
892 |
|
|
}
|
893 |
|
|
|
894 |
|
|
*q = inb_p(QIC02_DATA_PORT); /* read status byte */
|
895 |
|
|
|
896 |
|
|
if (TP_DIAGS(current_tape_dev))
|
897 |
|
|
printk("[%1d]=0x%x ", q-stp, (unsigned) (*q) & 0xff);
|
898 |
|
|
|
899 |
|
|
outb_p(ctlbits | QIC02_CTL_REQUEST, QIC02_CTL_PORT); /* set request */
|
900 |
|
|
|
901 |
|
|
while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0); /* wait for not ready */
|
902 |
|
|
|
903 |
|
|
udelay(22); /* delay >20 usec */
|
904 |
|
|
|
905 |
|
|
outb_p(ctlbits & ~QIC02_CTL_REQUEST, QIC02_CTL_PORT); /* un-set request */
|
906 |
|
|
|
907 |
|
|
}
|
908 |
|
|
|
909 |
|
|
/* Specs say we should wait for READY here.
|
910 |
|
|
* My drive doesn't seem to need it here yet, but others do?
|
911 |
|
|
*/
|
912 |
|
|
while (inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY)
|
913 |
|
|
/*skip*/; /* wait for ready */
|
914 |
|
|
|
915 |
|
|
if (TP_DIAGS(current_tape_dev))
|
916 |
|
|
printk("\n");
|
917 |
|
|
|
918 |
|
|
return TE_OK;
|
919 |
|
|
} /* rdstatus */
|
920 |
|
|
|
921 |
|
|
|
922 |
|
|
|
923 |
|
|
/* Get standard status (6 bytes).
|
924 |
|
|
* The `.dec' and `.urc' fields are in MSB-first byte-order,
|
925 |
|
|
* so they have to be swapped first.
|
926 |
|
|
*/
|
927 |
|
|
static int get_status(volatile struct tpstatus *stp)
|
928 |
|
|
{
|
929 |
|
|
int stat = rdstatus((char *) stp, TPSTATSIZE, QCMD_RD_STAT);
|
930 |
|
|
#if defined(i386) || defined(i486)
|
931 |
|
|
byte_swap_w(&(stp->dec));
|
932 |
|
|
byte_swap_w(&(stp->urc));
|
933 |
|
|
#else
|
934 |
|
|
/* should probably swap status bytes #definition */
|
935 |
|
|
#endif
|
936 |
|
|
return stat;
|
937 |
|
|
} /* get_status */
|
938 |
|
|
|
939 |
|
|
|
940 |
|
|
#if 0
|
941 |
|
|
/* This fails for my Wangtek drive */
|
942 |
|
|
/* get "Extended Status Register 3" (64 bytes)
|
943 |
|
|
*
|
944 |
|
|
* If the meaning of the returned bytes were known, the MT_TYPE
|
945 |
|
|
* identifier could be used to decode them, since they are
|
946 |
|
|
* "vendor unique". :-(
|
947 |
|
|
*/
|
948 |
|
|
static int get_ext_status3(void)
|
949 |
|
|
{
|
950 |
|
|
char vus[64]; /* vendor unique status */
|
951 |
|
|
int stat, i;
|
952 |
|
|
|
953 |
|
|
tpqputs(TPQD_ALWAYS, "Attempting to read Extended Status 3...");
|
954 |
|
|
stat = rdstatus(vus, sizeof(vus), QCMD_RD_STAT_X3);
|
955 |
|
|
if (stat != TE_OK)
|
956 |
|
|
return stat;
|
957 |
|
|
|
958 |
|
|
tpqputs(TPQD_ALWAYS, "Returned status bytes:");
|
959 |
|
|
for (i=0; i<sizeof(vus); i++) {
|
960 |
|
|
if ( i % 8 == 0 )
|
961 |
|
|
printk("\n" TPQIC02_NAME ": %2d:");
|
962 |
|
|
printk(" %2x", vus[i] & 0xff);
|
963 |
|
|
}
|
964 |
|
|
printk("\n");
|
965 |
|
|
|
966 |
|
|
return TE_OK;
|
967 |
|
|
} /* get_ext_status3 */
|
968 |
|
|
#endif
|
969 |
|
|
|
970 |
|
|
|
971 |
|
|
/* Read drive status and set generic status too.
|
972 |
|
|
* NOTE: Once we do a tp_sense(), read/write transfers are killed.
|
973 |
|
|
*/
|
974 |
|
|
static int tp_sense(int ignore)
|
975 |
|
|
{
|
976 |
|
|
unsigned err = 0, exnr = 0, gs = 0;
|
977 |
|
|
static void finish_rw(int cmd);
|
978 |
|
|
|
979 |
|
|
if (TPQDBG(SENSE_TEXT))
|
980 |
|
|
printk(TPQIC02_NAME ": tp_sense(ignore=0x%x) enter\n", ignore);
|
981 |
|
|
|
982 |
|
|
/* sense() is not allowed during a read or write cycle */
|
983 |
|
|
if (doing_write == YES)
|
984 |
|
|
tpqputs(TPQD_ALWAYS, "Warning: File Mark inserted because of sense() request");
|
985 |
|
|
/* The extra test is to avoid calling finish_rw during booting */
|
986 |
|
|
if ((doing_read!=NO) || (doing_write!=NO))
|
987 |
|
|
finish_rw(QCMD_RD_STAT);
|
988 |
|
|
|
989 |
|
|
if (get_status(&tperror) != TE_OK) {
|
990 |
|
|
tpqputs(TPQD_ALWAYS, "tp_sense: could not read tape drive status");
|
991 |
|
|
return TE_ERR;
|
992 |
|
|
}
|
993 |
|
|
|
994 |
|
|
err = tperror.exs; /* get exception status bits */
|
995 |
|
|
if (err & (TP_ST0|TP_ST1))
|
996 |
|
|
printk(TPQIC02_NAME ": tp_sense: status: %x, error count: %d, underruns: %d\n",
|
997 |
|
|
tperror.exs, tperror.dec, tperror.urc);
|
998 |
|
|
else if ((tperror.dec!=0) || (tperror.urc!=0) || TPQDBG(SENSE_CNTS))
|
999 |
|
|
printk(TPQIC02_NAME ": tp_sense: no hard errors, soft error count: %d, underruns: %d\n",
|
1000 |
|
|
tperror.dec, tperror.urc);
|
1001 |
|
|
|
1002 |
|
|
/* Set generic status. HP-UX defines these, but some extra would
|
1003 |
|
|
* be useful. Problem is to remain compatible. [Do we want to be
|
1004 |
|
|
* compatible??]
|
1005 |
|
|
*/
|
1006 |
|
|
if (err & TP_ST0) {
|
1007 |
|
|
if (err & TP_CNI) /* no cartridge */
|
1008 |
|
|
gs |= GMT_DR_OPEN(-1);
|
1009 |
|
|
if (status_dead == NO)
|
1010 |
|
|
gs |= GMT_ONLINE(-1); /* always online */
|
1011 |
|
|
if (err & TP_USL) /* not online */
|
1012 |
|
|
gs &= ~GMT_ONLINE(-1);
|
1013 |
|
|
if (err & TP_WRP)
|
1014 |
|
|
gs |= GMT_WR_PROT(-1);
|
1015 |
|
|
if (err & TP_EOM) { /* end of media */
|
1016 |
|
|
gs |= GMT_EOT(-1); /* not sure this is correct for writes */
|
1017 |
|
|
status_eom_detected = YES;
|
1018 |
|
|
/* I don't know whether drive always reports EOF at or before EOM. */
|
1019 |
|
|
status_eof_detected = YES;
|
1020 |
|
|
}
|
1021 |
|
|
/** if (err & TP_UDA) "Unrecoverable data error" **/
|
1022 |
|
|
/** if (err & TP_BNL) "Bad block not located" **/
|
1023 |
|
|
if (err & TP_FIL) {
|
1024 |
|
|
gs |= GMT_EOF(-1);
|
1025 |
|
|
status_eof_detected = YES;
|
1026 |
|
|
}
|
1027 |
|
|
}
|
1028 |
|
|
if (err & TP_ST1) {
|
1029 |
|
|
/** if (err & TP_ILL) "Illegal command" **/
|
1030 |
|
|
/** if (err & TP_NDT) "No data detected" **/
|
1031 |
|
|
/** if (err & TP_MBD) "Marginal block detected" **/
|
1032 |
|
|
if (err & TP_BOM)
|
1033 |
|
|
gs |= GMT_BOT(-1); /* beginning of tape */
|
1034 |
|
|
}
|
1035 |
|
|
ioctl_status.mt_gstat = gs;
|
1036 |
|
|
ioctl_status.mt_dsreg = tperror.exs; /* "drive status" */
|
1037 |
|
|
ioctl_status.mt_erreg = tperror.dec; /* "sense key error" */
|
1038 |
|
|
|
1039 |
|
|
if (err & (TP_ST0|TP_ST1)) {
|
1040 |
|
|
/* My Wangtek occasionally reports `status' 1212 which should be ignored. */
|
1041 |
|
|
exnr = decode_exception_nr(err);
|
1042 |
|
|
handle_exception(exnr, err); /* update driver state wrt drive status */
|
1043 |
|
|
report_exception(exnr);
|
1044 |
|
|
}
|
1045 |
|
|
err &= ~ignore; /* mask unwanted errors -- not the correct way, use exception nrs?? */
|
1046 |
|
|
if (((err & TP_ST0) && (err & REPORT_ERR0)) ||
|
1047 |
|
|
((err & TP_ST1) && (err & REPORT_ERR1)))
|
1048 |
|
|
return TE_ERR;
|
1049 |
|
|
return TE_OK;
|
1050 |
|
|
} /* tp_sense */
|
1051 |
|
|
|
1052 |
|
|
|
1053 |
|
|
|
1054 |
|
|
/* Wait for a wind or rewind operation to finish or
|
1055 |
|
|
* to time-out. (May take very long).
|
1056 |
|
|
*/
|
1057 |
|
|
static int wait_for_rewind(time_t timeout)
|
1058 |
|
|
{
|
1059 |
|
|
int stat;
|
1060 |
|
|
|
1061 |
|
|
stat = inb(QIC02_STAT_PORT) & QIC02_STAT_MASK;
|
1062 |
|
|
if (TPQDBG(REWIND))
|
1063 |
|
|
printk(TPQIC02_NAME ": Waiting for (re-)wind to finish: stat=0x%x\n", stat);
|
1064 |
|
|
|
1065 |
|
|
stat = wait_for_ready(timeout);
|
1066 |
|
|
|
1067 |
|
|
if (stat != TE_OK) {
|
1068 |
|
|
tpqputs(TPQD_ALWAYS, "(re-) winding failed\n");
|
1069 |
|
|
}
|
1070 |
|
|
return stat;
|
1071 |
|
|
} /* wait_for_rewind */
|
1072 |
|
|
|
1073 |
|
|
|
1074 |
|
|
|
1075 |
|
|
/* Perform a full QIC02 command, and wait for completion,
|
1076 |
|
|
* check status when done. Complain about exceptions.
|
1077 |
|
|
*
|
1078 |
|
|
* This function should return an OS error code when
|
1079 |
|
|
* something goes wrong, 0 otherwise.
|
1080 |
|
|
*/
|
1081 |
|
|
static int ll_do_qic_cmd(int cmd, time_t timeout)
|
1082 |
|
|
{
|
1083 |
|
|
int stat;
|
1084 |
|
|
|
1085 |
|
|
if (status_dead == YES) {
|
1086 |
|
|
tpqputs(TPQD_ALWAYS, "Drive is dead. Do a `mt reset`.");
|
1087 |
|
|
return -ENXIO; /* User should do an MTRESET. */
|
1088 |
|
|
}
|
1089 |
|
|
|
1090 |
|
|
stat = wait_for_ready(timeout); /* wait for ready or exception */
|
1091 |
|
|
if (stat == TE_EX) {
|
1092 |
|
|
if (tp_sense(TP_WRP|TP_BOM|TP_EOM|TP_FIL)!=TE_OK)
|
1093 |
|
|
return -EIO;
|
1094 |
|
|
/* else nothing to worry about, I hope */
|
1095 |
|
|
stat = TE_OK;
|
1096 |
|
|
}
|
1097 |
|
|
if (stat != TE_OK) {
|
1098 |
|
|
printk(TPQIC02_NAME ": ll_do_qic_cmd(%x, %ld) failed\n", cmd, (long) timeout);
|
1099 |
|
|
return -EIO;
|
1100 |
|
|
}
|
1101 |
|
|
|
1102 |
|
|
|
1103 |
|
|
#if OBSOLETE
|
1104 |
|
|
/* wait for ready since it may not be active immediately after reading status */
|
1105 |
|
|
while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) != 0);
|
1106 |
|
|
#endif
|
1107 |
|
|
|
1108 |
|
|
stat = send_qic02_cmd(cmd, timeout, 0); /* (checks for exceptions) */
|
1109 |
|
|
|
1110 |
|
|
if (cmd==QCMD_RD_FM) {
|
1111 |
|
|
status_eof_detected = NO;
|
1112 |
|
|
ioctl_status.mt_fileno++;
|
1113 |
|
|
/* Should update block count as well, but can't.
|
1114 |
|
|
* Can do a `read address' for some drives, when MTNOP is done.
|
1115 |
|
|
*/
|
1116 |
|
|
} else if (cmd==QCMD_WRT_FM) {
|
1117 |
|
|
status_eof_detected = NO;
|
1118 |
|
|
ioctl_status.mt_fileno++;
|
1119 |
|
|
} else if ((cmd==QCMD_REWIND) || (cmd==QCMD_ERASE) || (cmd==QCMD_RETEN)) {
|
1120 |
|
|
status_eof_detected = NO;
|
1121 |
|
|
status_eom_detected = NO;
|
1122 |
|
|
status_eot_detected = NO;
|
1123 |
|
|
need_rewind = NO;
|
1124 |
|
|
ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
|
1125 |
|
|
extra_blocks_left = BLOCKS_BEYOND_EW;
|
1126 |
|
|
return_write_eof = NO;
|
1127 |
|
|
return_read_eof = NO;
|
1128 |
|
|
reported_read_eof = NO;
|
1129 |
|
|
reported_write_eof = NO;
|
1130 |
|
|
}
|
1131 |
|
|
/* sense() will set eof/eom as required */
|
1132 |
|
|
if (stat==TE_EX) {
|
1133 |
|
|
if (tp_sense(TP_WRP|TP_BOM|TP_EOM|TP_FIL)!=TE_OK) {
|
1134 |
|
|
printk(TPQIC02_NAME ": Exception persist in ll_do_qic_cmd[1](%x, %ld)", cmd, (long) timeout);
|
1135 |
|
|
status_dead = YES;
|
1136 |
|
|
return -ENXIO;
|
1137 |
|
|
/* if rdstatus fails too, we're in trouble */
|
1138 |
|
|
}
|
1139 |
|
|
}
|
1140 |
|
|
else if (stat!=TE_OK) {
|
1141 |
|
|
printk(TPQIC02_NAME ": ll_do_qic_cmd: send_qic02_cmd failed, stat = 0x%x\n", stat);
|
1142 |
|
|
return -EIO; /*** -EIO is probably not always appropriate */
|
1143 |
|
|
}
|
1144 |
|
|
|
1145 |
|
|
|
1146 |
|
|
if (timeout == TIM_R)
|
1147 |
|
|
stat = wait_for_rewind(timeout);
|
1148 |
|
|
else
|
1149 |
|
|
stat = wait_for_ready(timeout);
|
1150 |
|
|
|
1151 |
|
|
if (stat==TE_EX) {
|
1152 |
|
|
if (tp_sense((cmd==QCMD_SEEK_EOD ? /*****************************/
|
1153 |
|
|
TP_EOR|TP_NDT|TP_UDA|TP_BNL|TP_WRP|TP_BOM|TP_EOM|TP_FIL :
|
1154 |
|
|
TP_WRP|TP_BOM|TP_EOM|TP_FIL))!=TE_OK) {
|
1155 |
|
|
printk(TPQIC02_NAME ": Exception persist in ll_do_qic_cmd[2](%x, %ld)\n", cmd, (long) timeout);
|
1156 |
|
|
if (cmd!=QCMD_RD_FM)
|
1157 |
|
|
status_dead = YES;
|
1158 |
|
|
return -ENXIO;
|
1159 |
|
|
/* if rdstatus fails too, we're in trouble */
|
1160 |
|
|
}
|
1161 |
|
|
}
|
1162 |
|
|
else if (stat!=TE_OK) {
|
1163 |
|
|
printk(TPQIC02_NAME ": ll_do_qic_cmd %x: wait failed, stat == 0x%x\n", cmd, stat);
|
1164 |
|
|
return -EIO;
|
1165 |
|
|
}
|
1166 |
|
|
return 0;
|
1167 |
|
|
} /* ll_do_qic_cmd */
|
1168 |
|
|
|
1169 |
|
|
|
1170 |
|
|
/*
|
1171 |
|
|
* Problem: What to do when the user cancels a read/write operation
|
1172 |
|
|
* in-progress?
|
1173 |
|
|
*
|
1174 |
|
|
* "Deactivating ONLINE during a READ also causes the"
|
1175 |
|
|
* "tape to be rewound to BOT." Ditto for WRITEs, except
|
1176 |
|
|
* a FM is written first. "The host may alternatively terminate
|
1177 |
|
|
* the READ/WRITE command by issuing a RFM/WFM command."
|
1178 |
|
|
*
|
1179 |
|
|
* For READs:
|
1180 |
|
|
* Neither option will leave the tape positioned where it was.
|
1181 |
|
|
* Another (better?) solution is to terminate the READ by two
|
1182 |
|
|
* subsequent sense() operations, the first to stop the current
|
1183 |
|
|
* READ cycle, the second to clear the `Illegal command' exception,
|
1184 |
|
|
* because the QIC-02 specs didn't anticipate this. This is
|
1185 |
|
|
* delayed until actually needed, so a tar listing can be aborted
|
1186 |
|
|
* by the user and continued later.
|
1187 |
|
|
* If anybody has a better solution, let me know! [Also, let me
|
1188 |
|
|
* know if your drive (mine is a Wangtek5150EQ) does not accept
|
1189 |
|
|
* this sequence for canceling the read-cycle.]
|
1190 |
|
|
*
|
1191 |
|
|
* For WRITEs it's simple: Just do a WRITE_FM, leaving the tape
|
1192 |
|
|
* positioned after the FM.
|
1193 |
|
|
*/
|
1194 |
|
|
|
1195 |
|
|
static void terminate_read(int cmd)
|
1196 |
|
|
{
|
1197 |
|
|
if (doing_read == YES) {
|
1198 |
|
|
doing_read = NO;
|
1199 |
|
|
if (cmd != QCMD_RD_FM) {
|
1200 |
|
|
/* if the command is a RFM, there is no need to do this
|
1201 |
|
|
* because a RFM will legally terminate the read-cycle.
|
1202 |
|
|
*/
|
1203 |
|
|
tpqputs(TPQD_ALWAYS, "terminating pending read-cycle");
|
1204 |
|
|
|
1205 |
|
|
/* I'm not too sure about this part -- hhb */
|
1206 |
|
|
if (QIC02_TAPE_IFC == MOUNTAIN) {
|
1207 |
|
|
/* Mountain reference says can terminate by de-asserting online */
|
1208 |
|
|
ctlbits &= ~MTN_QIC02_CTL_ONLINE;
|
1209 |
|
|
}
|
1210 |
|
|
|
1211 |
|
|
if (tp_sense(TP_FIL|TP_EOM|TP_WRP) != TE_OK) {
|
1212 |
|
|
tpqputs(TPQD_ALWAYS, "finish_rw[read1]: ignore the 2 lines above");
|
1213 |
|
|
if (is_exception()) {
|
1214 |
|
|
if (tp_sense(TP_ILL|TP_FIL|TP_EOM|TP_WRP) != TE_OK)
|
1215 |
|
|
tpqputs(TPQD_ALWAYS, "finish_rw[read2]: read cycle error");
|
1216 |
|
|
}
|
1217 |
|
|
}
|
1218 |
|
|
}
|
1219 |
|
|
}
|
1220 |
|
|
} /* terminate_read */
|
1221 |
|
|
|
1222 |
|
|
|
1223 |
|
|
static void terminate_write(int cmd)
|
1224 |
|
|
{
|
1225 |
|
|
int stat;
|
1226 |
|
|
|
1227 |
|
|
if (doing_write == YES) {
|
1228 |
|
|
doing_write = NO;
|
1229 |
|
|
/* Finish writing by appending a FileMark at the end. */
|
1230 |
|
|
if (cmd != QCMD_WRT_FM) {
|
1231 |
|
|
/* finish off write cycle */
|
1232 |
|
|
stat = ll_do_qic_cmd(QCMD_WRT_FM, TIM_M);
|
1233 |
|
|
if (stat != TE_OK)
|
1234 |
|
|
tpqputs(TPQD_ALWAYS, "Couldn't finish write cycle properly");
|
1235 |
|
|
(void) tp_sense(0);
|
1236 |
|
|
}
|
1237 |
|
|
/* If there is an EOF token waiting to be returned to
|
1238 |
|
|
* the (writing) application, discard it now.
|
1239 |
|
|
* We could be at EOT, so don't reset return_write_eof.
|
1240 |
|
|
*/
|
1241 |
|
|
reported_write_eof=YES;
|
1242 |
|
|
}
|
1243 |
|
|
} /* terminate_write */
|
1244 |
|
|
|
1245 |
|
|
|
1246 |
|
|
/* terminate read or write cycle because of command `cmd' */
|
1247 |
|
|
static void finish_rw(int cmd)
|
1248 |
|
|
{
|
1249 |
|
|
if (wait_for_ready(TIM_S) != TE_OK) {
|
1250 |
|
|
tpqputs(TPQD_ALWAYS, "error: drive not ready in finish_rw() !");
|
1251 |
|
|
return;
|
1252 |
|
|
}
|
1253 |
|
|
terminate_read(cmd);
|
1254 |
|
|
terminate_write(cmd);
|
1255 |
|
|
} /* finish_rw */
|
1256 |
|
|
|
1257 |
|
|
|
1258 |
|
|
/* Perform a QIC command through ll_do_qic_cmd().
|
1259 |
|
|
* If necessary, rewind the tape first.
|
1260 |
|
|
* Return an OS error code if something goes wrong, 0 if all is well.
|
1261 |
|
|
*/
|
1262 |
|
|
static int do_qic_cmd(int cmd, time_t timeout)
|
1263 |
|
|
{
|
1264 |
|
|
int stat;
|
1265 |
|
|
|
1266 |
|
|
|
1267 |
|
|
finish_rw(cmd);
|
1268 |
|
|
|
1269 |
|
|
if (need_rewind) {
|
1270 |
|
|
tpqputs(TPQD_REWIND, "Rewinding tape...");
|
1271 |
|
|
stat = ll_do_qic_cmd(QCMD_REWIND, TIM_R);
|
1272 |
|
|
if (stat != 0) {
|
1273 |
|
|
printk(TPQIC02_NAME ": rewind failed in do_qic_cmd(). stat=0x%2x", stat);
|
1274 |
|
|
return stat;
|
1275 |
|
|
}
|
1276 |
|
|
need_rewind = NO;
|
1277 |
|
|
if (cmd==QCMD_REWIND) /* don't wind beyond BOT ;-) */
|
1278 |
|
|
return 0;
|
1279 |
|
|
}
|
1280 |
|
|
|
1281 |
|
|
return ll_do_qic_cmd(cmd, timeout);
|
1282 |
|
|
} /* do_qic_cmd */
|
1283 |
|
|
|
1284 |
|
|
|
1285 |
|
|
/* Not all ioctls are supported for all drives. Some rely on
|
1286 |
|
|
* optional QIC-02 commands. Check tpqic02.h for configuration.
|
1287 |
|
|
* Some of these commands may require ONLINE to be active.
|
1288 |
|
|
*/
|
1289 |
|
|
static int do_ioctl_cmd(int cmd)
|
1290 |
|
|
{
|
1291 |
|
|
int stat;
|
1292 |
|
|
|
1293 |
|
|
/* It is not permitted to read or wind the tape after bytes have
|
1294 |
|
|
* been written. It is not permitted to write the tape while in
|
1295 |
|
|
* read mode.
|
1296 |
|
|
* We try to be kind and allow reading again after writing a FM...
|
1297 |
|
|
*/
|
1298 |
|
|
|
1299 |
|
|
switch (cmd) {
|
1300 |
|
|
case MTRESET:
|
1301 |
|
|
/* reset verbose */
|
1302 |
|
|
return (tape_reset(1)==TE_OK)? 0 : -EIO;
|
1303 |
|
|
|
1304 |
|
|
case MTFSF:
|
1305 |
|
|
tpqputs(TPQD_IOCTLS, "MTFSF forward searching filemark");
|
1306 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1307 |
|
|
return -EACCES;
|
1308 |
|
|
return do_qic_cmd(QCMD_RD_FM, TIM_F);
|
1309 |
|
|
|
1310 |
|
|
case MTBSF:
|
1311 |
|
|
if (TP_HAVE_BSF) {
|
1312 |
|
|
tpqputs(TPQD_IOCTLS, "MTBSF backward searching filemark -- optional command");
|
1313 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1314 |
|
|
return -EACCES;
|
1315 |
|
|
stat = do_qic_cmd(QCMD_RD_FM_BCK, TIM_F);
|
1316 |
|
|
} else {
|
1317 |
|
|
stat = -ENXIO;
|
1318 |
|
|
}
|
1319 |
|
|
status_eom_detected = status_eof_detected = NO;
|
1320 |
|
|
return stat;
|
1321 |
|
|
|
1322 |
|
|
case MTFSR:
|
1323 |
|
|
if (TP_HAVE_FSR) { /* This is an optional QIC-02 command */
|
1324 |
|
|
tpqputs(TPQD_IOCTLS, "MTFSR forward space record");
|
1325 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1326 |
|
|
return -EACCES;
|
1327 |
|
|
stat = do_qic_cmd(QCMD_SPACE_FWD, TIM_F);
|
1328 |
|
|
} else {
|
1329 |
|
|
/**** fake it by doing a read data block command? ******/
|
1330 |
|
|
tpqputs(TPQD_IOCTLS, "MTFSR not supported");
|
1331 |
|
|
stat = -ENXIO;
|
1332 |
|
|
}
|
1333 |
|
|
return stat;
|
1334 |
|
|
|
1335 |
|
|
case MTBSR:
|
1336 |
|
|
if (TP_HAVE_BSR) { /* This is an optional QIC-02 command */
|
1337 |
|
|
/* we need this for appending files with GNU tar!! */
|
1338 |
|
|
tpqputs(TPQD_IOCTLS, "MTFSR backward space record");
|
1339 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1340 |
|
|
return -EACCES;
|
1341 |
|
|
stat = do_qic_cmd(QCMD_SPACE_BCK, TIM_F);
|
1342 |
|
|
} else {
|
1343 |
|
|
tpqputs(TPQD_IOCTLS, "MTBSR not supported");
|
1344 |
|
|
stat = -ENXIO;
|
1345 |
|
|
}
|
1346 |
|
|
status_eom_detected = status_eof_detected = NO;
|
1347 |
|
|
return stat;
|
1348 |
|
|
|
1349 |
|
|
case MTWEOF:
|
1350 |
|
|
tpqputs(TPQD_IOCTLS, "MTWEOF write eof mark");
|
1351 |
|
|
/* Plain GNU mt(1) 2.2 uses read-only mode for writing FM. :-( */
|
1352 |
|
|
if (mode_access==READ)
|
1353 |
|
|
return -EACCES;
|
1354 |
|
|
|
1355 |
|
|
/* allow tape movement after writing FM */
|
1356 |
|
|
status_bytes_rd = status_bytes_wr; /* Kludge-O-Matic */
|
1357 |
|
|
status_bytes_wr = NO;
|
1358 |
|
|
return do_qic_cmd(QCMD_WRT_FM, TIM_M);
|
1359 |
|
|
/* not sure what to do with status_bytes when WFM should fail */
|
1360 |
|
|
|
1361 |
|
|
case MTREW:
|
1362 |
|
|
tpqputs(TPQD_IOCTLS, "MTREW rewinding tape");
|
1363 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1364 |
|
|
return -EACCES;
|
1365 |
|
|
status_eom_detected = status_eof_detected = NO;
|
1366 |
|
|
return do_qic_cmd(QCMD_REWIND, TIM_R);
|
1367 |
|
|
|
1368 |
|
|
case MTOFFL:
|
1369 |
|
|
tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline");
|
1370 |
|
|
/* Doing a drive select will clear (unlock) the current drive.
|
1371 |
|
|
* But that requires support for multiple drives and locking.
|
1372 |
|
|
*/
|
1373 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1374 |
|
|
return -EACCES;
|
1375 |
|
|
status_eom_detected = status_eof_detected = NO;
|
1376 |
|
|
/**** do rewind depending on minor bits??? ***/
|
1377 |
|
|
stat = do_qic_cmd(QCMD_REWIND, TIM_R);
|
1378 |
|
|
return stat;
|
1379 |
|
|
|
1380 |
|
|
case MTNOP:
|
1381 |
|
|
tpqputs(TPQD_IOCTLS, "MTNOP setting status only");
|
1382 |
|
|
/********** should do `read position' for drives that support it **********/
|
1383 |
|
|
return (tp_sense(-1)==TE_OK)? 0 : -EIO; /**** check return codes ****/
|
1384 |
|
|
|
1385 |
|
|
case MTRETEN:
|
1386 |
|
|
tpqputs(TPQD_IOCTLS, "MTRETEN retension tape");
|
1387 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1388 |
|
|
return -EACCES;
|
1389 |
|
|
status_eom_detected = status_eof_detected = NO;
|
1390 |
|
|
return do_qic_cmd(QCMD_RETEN, TIM_R);
|
1391 |
|
|
|
1392 |
|
|
case MTBSFM:
|
1393 |
|
|
/* Think think is like MTBSF, except that
|
1394 |
|
|
* we shouldn't skip the FM. Tricky.
|
1395 |
|
|
* Maybe use RD_FM_BCK, then do a SPACE_FWD?
|
1396 |
|
|
*/
|
1397 |
|
|
tpqputs(TPQD_IOCTLS, "MTBSFM not supported");
|
1398 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1399 |
|
|
return -EACCES;
|
1400 |
|
|
return -ENXIO;
|
1401 |
|
|
|
1402 |
|
|
case MTFSFM:
|
1403 |
|
|
/* I think this is like MTFSF, except that
|
1404 |
|
|
* we shouldn't skip the FM. Tricky.
|
1405 |
|
|
* Maybe use QCMD_RD_DATA until we get a TP_FIL exception?
|
1406 |
|
|
* But then the FM will have been skipped...
|
1407 |
|
|
* Maybe use RD_FM, then RD_FM_BCK, but not all
|
1408 |
|
|
* drives will support that!
|
1409 |
|
|
*/
|
1410 |
|
|
tpqputs(TPQD_IOCTLS, "MTFSFM not supported");
|
1411 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1412 |
|
|
return -EACCES;
|
1413 |
|
|
return -ENXIO;
|
1414 |
|
|
|
1415 |
|
|
case MTEOM:
|
1416 |
|
|
/* This should leave the tape ready for appending
|
1417 |
|
|
* another file to the end, such that it would append
|
1418 |
|
|
* after the last FM on tape.
|
1419 |
|
|
*/
|
1420 |
|
|
tpqputs(TPQD_IOCTLS, "MTEOM search for End Of recorded Media");
|
1421 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1422 |
|
|
return -EACCES;
|
1423 |
|
|
if (TP_HAVE_EOD) {
|
1424 |
|
|
/* Use faster seeking when possible.
|
1425 |
|
|
* This requires the absence of data beyond the EOM.
|
1426 |
|
|
* It seems that my drive does not always perform the
|
1427 |
|
|
* SEEK_EOD correctly, unless it is preceded by a
|
1428 |
|
|
* rewind command.
|
1429 |
|
|
*/
|
1430 |
|
|
# if 0
|
1431 |
|
|
status_eom_detected = status_eof_detected = NO;
|
1432 |
|
|
# endif
|
1433 |
|
|
stat = do_qic_cmd(QCMD_REWIND, TIM_R);
|
1434 |
|
|
if (stat)
|
1435 |
|
|
return stat;
|
1436 |
|
|
stat = do_qic_cmd(QCMD_SEEK_EOD, TIM_F);
|
1437 |
|
|
/* After a successful seek, TP_EOR should be returned */
|
1438 |
|
|
} else {
|
1439 |
|
|
/* else just seek until the drive returns exception "No Data" */
|
1440 |
|
|
stat = 0;
|
1441 |
|
|
while ((stat==0) && (!status_eom_detected)) {
|
1442 |
|
|
stat = do_qic_cmd(QCMD_RD_FM, TIM_F); /***** should use MTFSFM here???? ******/
|
1443 |
|
|
}
|
1444 |
|
|
if (tperror.exs & TP_NDT)
|
1445 |
|
|
return 0;
|
1446 |
|
|
}
|
1447 |
|
|
return stat;
|
1448 |
|
|
|
1449 |
|
|
case MTERASE:
|
1450 |
|
|
tpqputs(TPQD_IOCTLS, "MTERASE -- ERASE TAPE !");
|
1451 |
|
|
if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {
|
1452 |
|
|
tpqputs(TPQD_ALWAYS, "Cartridge is write-protected.");
|
1453 |
|
|
return -EACCES;
|
1454 |
|
|
} else {
|
1455 |
|
|
time_t t = jiffies;
|
1456 |
|
|
|
1457 |
|
|
/* Plain GNU mt(1) 2.2 erases a tape in O_RDONLY. :-( */
|
1458 |
|
|
if (mode_access==READ)
|
1459 |
|
|
return -EACCES;
|
1460 |
|
|
|
1461 |
|
|
/* give user a few seconds to pull out tape */
|
1462 |
|
|
while (jiffies - t < 4*HZ)
|
1463 |
|
|
schedule();
|
1464 |
|
|
}
|
1465 |
|
|
|
1466 |
|
|
/* don't bother writing filemark first */
|
1467 |
|
|
status_eom_detected = status_eof_detected = NO;
|
1468 |
|
|
return do_qic_cmd(QCMD_ERASE, TIM_R);
|
1469 |
|
|
|
1470 |
|
|
case MTRAS1:
|
1471 |
|
|
if (TP_HAVE_RAS1) {
|
1472 |
|
|
tpqputs(TPQD_IOCTLS, "MTRAS1: non-destructive self test");
|
1473 |
|
|
stat = do_qic_cmd(QCMD_SELF_TST1, TIM_R);
|
1474 |
|
|
if (stat != 0) {
|
1475 |
|
|
tpqputs(TPQD_ALWAYS, "RAS1 failed");
|
1476 |
|
|
return stat;
|
1477 |
|
|
}
|
1478 |
|
|
return (tp_sense(0)==TE_OK)? 0 : -EIO; /* get_ext_status3(); */
|
1479 |
|
|
}
|
1480 |
|
|
tpqputs(TPQD_IOCTLS, "RAS1 not supported");
|
1481 |
|
|
return -ENXIO;
|
1482 |
|
|
|
1483 |
|
|
case MTRAS2:
|
1484 |
|
|
if (TP_HAVE_RAS2) {
|
1485 |
|
|
tpqputs(TPQD_IOCTLS, "MTRAS2: destructive self test");
|
1486 |
|
|
stat = do_qic_cmd(QCMD_SELF_TST2, TIM_R);
|
1487 |
|
|
if (stat != 0) {
|
1488 |
|
|
tpqputs(TPQD_ALWAYS, "RAS2 failed");
|
1489 |
|
|
return stat;
|
1490 |
|
|
}
|
1491 |
|
|
return (tp_sense(0)==TE_OK)? 0 : -EIO; /* get_ext_status3(); */
|
1492 |
|
|
}
|
1493 |
|
|
tpqputs(TPQD_IOCTLS, "RAS2 not supported");
|
1494 |
|
|
return -ENXIO;
|
1495 |
|
|
|
1496 |
|
|
case MTSEEK:
|
1497 |
|
|
if (TP_HAVE_SEEK && (QIC02_TAPE_IFC==ARCHIVE)) {
|
1498 |
|
|
tpqputs(TPQD_IOCTLS, "MTSEEK seeking block");
|
1499 |
|
|
if ((mode_access==WRITE) && status_bytes_wr)
|
1500 |
|
|
return -EACCES;
|
1501 |
|
|
/* NOTE: address (24 bits) is in seek_addr_buf[] */
|
1502 |
|
|
return do_qic_cmd(AR_QCMDV_SEEK_BLK, TIM_F);
|
1503 |
|
|
}
|
1504 |
|
|
else
|
1505 |
|
|
return -ENOTTY;
|
1506 |
|
|
|
1507 |
|
|
default:
|
1508 |
|
|
return -ENOTTY;
|
1509 |
|
|
}
|
1510 |
|
|
} /* do_ioctl_cmd */
|
1511 |
|
|
|
1512 |
|
|
|
1513 |
|
|
/* dma_transfer(): This routine is called for every 512 bytes to be read
|
1514 |
|
|
* from/written to the tape controller. Speed is important here!
|
1515 |
|
|
* (There must be enough time left for the hd controller!)
|
1516 |
|
|
* When other devices use DMA they must ensure they use un-interruptible
|
1517 |
|
|
* double byte accesses to the DMA controller. Floppy.c is ok.
|
1518 |
|
|
* Must have interrupts disabled when this function is invoked,
|
1519 |
|
|
* otherwise, the double-byte transfers to the DMA controller will not
|
1520 |
|
|
* be atomic. That could lead to nasty problems when they are interrupted
|
1521 |
|
|
* by other DMA interrupt-routines.
|
1522 |
|
|
*
|
1523 |
|
|
* This routine merely does the least possible to keep
|
1524 |
|
|
* the transfers going:
|
1525 |
|
|
* - set the DMA count register for the next 512 bytes
|
1526 |
|
|
* - adjust the DMA address and page registers
|
1527 |
|
|
* - adjust the timeout
|
1528 |
|
|
* - tell the tape controller to start transferring
|
1529 |
|
|
* We assume the dma address and mode are, and remain, valid.
|
1530 |
|
|
*/
|
1531 |
|
|
static inline void dma_transfer(void)
|
1532 |
|
|
{
|
1533 |
|
|
|
1534 |
|
|
if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */
|
1535 |
|
|
outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT); /* back to normal */
|
1536 |
|
|
else if (QIC02_TAPE_IFC == ARCHIVE)
|
1537 |
|
|
outb_p(0, AR_RESET_DMA_PORT);
|
1538 |
|
|
else /* QIC02_TAPE_IFC == MOUNTAIN */
|
1539 |
|
|
outb_p(ctlbits, QIC02_CTL_PORT);
|
1540 |
|
|
|
1541 |
|
|
|
1542 |
|
|
clear_dma_ff(QIC02_TAPE_DMA);
|
1543 |
|
|
set_dma_mode(QIC02_TAPE_DMA, dma_mode);
|
1544 |
|
|
set_dma_addr(QIC02_TAPE_DMA, buffaddr+dma_bytes_done); /* full address */
|
1545 |
|
|
set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE);
|
1546 |
|
|
|
1547 |
|
|
/* start tape DMA controller */
|
1548 |
|
|
if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */
|
1549 |
|
|
outb_p(WT_CTL_DMA | WT_CTL_ONLINE, QIC02_CTL_PORT); /* trigger DMA transfer */
|
1550 |
|
|
|
1551 |
|
|
else if (QIC02_TAPE_IFC == ARCHIVE) {
|
1552 |
|
|
outb_p(AR_CTL_IEN | AR_CTL_DNIEN, QIC02_CTL_PORT); /* enable interrupts again */
|
1553 |
|
|
outb_p(0, AR_START_DMA_PORT); /* start DMA transfer */
|
1554 |
|
|
/* In dma_end() AR_RESET_DMA_PORT is written too. */
|
1555 |
|
|
|
1556 |
|
|
} else /* QIC02_TAPE_IFC == MOUNTAIN */ {
|
1557 |
|
|
inb(MTN_R_DESELECT_DMA_PORT);
|
1558 |
|
|
outb_p(ctlbits | (MTN_CTL_EXC_IEN | MTN_CTL_DNIEN), QIC02_CTL_PORT);
|
1559 |
|
|
outb_p(0, MTN_W_SELECT_DMA_PORT); /* start DMA transfer */
|
1560 |
|
|
if (dma_mode == DMA_MODE_WRITE)
|
1561 |
|
|
outb_p(0, MTN_W_DMA_WRITE_PORT); /* start DMA transfer */
|
1562 |
|
|
}
|
1563 |
|
|
|
1564 |
|
|
/* start computer DMA controller */
|
1565 |
|
|
enable_dma(QIC02_TAPE_DMA);
|
1566 |
|
|
/* block transfer should start now, jumping to the
|
1567 |
|
|
* interrupt routine when done or an exception was detected.
|
1568 |
|
|
*/
|
1569 |
|
|
} /* dma_transfer */
|
1570 |
|
|
|
1571 |
|
|
|
1572 |
|
|
/* start_dma() sets a DMA transfer up between the tape controller and
|
1573 |
|
|
* the kernel qic02_tape_buf buffer.
|
1574 |
|
|
* Normally bytes_todo==dma_bytes_done at the end of a DMA transfer. If not,
|
1575 |
|
|
* a filemark was read, or an attempt to write beyond the End Of Tape
|
1576 |
|
|
* was made. [Or some other bad thing happened.]
|
1577 |
|
|
* Must do a sense() before returning error.
|
1578 |
|
|
*/
|
1579 |
|
|
static int start_dma(short mode, unsigned long bytes_todo)
|
1580 |
|
|
/* assume 'bytes_todo'>0 */
|
1581 |
|
|
{
|
1582 |
|
|
int stat;
|
1583 |
|
|
|
1584 |
|
|
tpqputs(TPQD_DEBUG, "start_dma() enter");
|
1585 |
|
|
TPQDEB({printk(TPQIC02_NAME ": doing_read==%d, doing_write==%d\n", doing_read, doing_write);})
|
1586 |
|
|
|
1587 |
|
|
dma_bytes_done = 0;
|
1588 |
|
|
dma_bytes_todo = bytes_todo;
|
1589 |
|
|
status_error = NO;
|
1590 |
|
|
/* dma_mode!=0 indicates that the dma controller is in use */
|
1591 |
|
|
dma_mode = (mode == WRITE)? DMA_MODE_WRITE : DMA_MODE_READ;
|
1592 |
|
|
|
1593 |
|
|
/* Only give READ/WRITE DATA command to tape drive if we haven't
|
1594 |
|
|
* done that already. Otherwise the drive will rewind to the beginning
|
1595 |
|
|
* of the current file on tape. Any QIC command given other than
|
1596 |
|
|
* R/W FM will break the read/write transfer cycle.
|
1597 |
|
|
* do_qic_cmd() will terminate doing_{read,write}
|
1598 |
|
|
*/
|
1599 |
|
|
if ((doing_read == NO) && (doing_write == NO)) {
|
1600 |
|
|
/* First, we have to clear the status -- maybe remove TP_FIL???
|
1601 |
|
|
*/
|
1602 |
|
|
|
1603 |
|
|
#if 0
|
1604 |
|
|
/* Next dummy get status is to make sure CNI is valid,
|
1605 |
|
|
since we're only just starting a read/write it doesn't
|
1606 |
|
|
matter some exceptions are cleared by reading the status;
|
1607 |
|
|
we're only interested in CNI and WRP. -Eddy */
|
1608 |
|
|
get_status(&tperror);
|
1609 |
|
|
#else
|
1610 |
|
|
/* TP_CNI should now be handled in open(). -Hennus */
|
1611 |
|
|
#endif
|
1612 |
|
|
|
1613 |
|
|
stat = tp_sense(((mode == WRITE)? 0 : TP_WRP) | TP_BOM | TP_FIL);
|
1614 |
|
|
if (stat != TE_OK)
|
1615 |
|
|
return stat;
|
1616 |
|
|
|
1617 |
|
|
#if OBSOLETE
|
1618 |
|
|
/************* not needed iff rd_status() would wait for ready!!!!!! **********/
|
1619 |
|
|
if (wait_for_ready(TIM_S) != TE_OK) { /*** not sure this is needed ***/
|
1620 |
|
|
tpqputs(TPQD_ALWAYS, "wait_for_ready failed in start_dma");
|
1621 |
|
|
return -EIO;
|
1622 |
|
|
}
|
1623 |
|
|
#endif
|
1624 |
|
|
|
1625 |
|
|
if (QIC02_TAPE_IFC == MOUNTAIN) {
|
1626 |
|
|
/* Set control bits to select ONLINE during command */
|
1627 |
|
|
ctlbits |= MTN_QIC02_CTL_ONLINE;
|
1628 |
|
|
}
|
1629 |
|
|
|
1630 |
|
|
/* Tell the controller the data direction */
|
1631 |
|
|
|
1632 |
|
|
/* r/w, timeout medium, check exceptions, sets status_cmd_pending. */
|
1633 |
|
|
stat = send_qic02_cmd((mode == WRITE)? QCMD_WRT_DATA : QCMD_RD_DATA, TIM_M, 0);
|
1634 |
|
|
if (stat!=TE_OK) {
|
1635 |
|
|
printk(TPQIC02_NAME ": start_dma: init %s failed\n",
|
1636 |
|
|
(mode == WRITE)? "write" : "read");
|
1637 |
|
|
(void) tp_sense(0);
|
1638 |
|
|
return stat;
|
1639 |
|
|
}
|
1640 |
|
|
|
1641 |
|
|
/* Do this last, because sense() will clear the doing_{read,write}
|
1642 |
|
|
* flags, causing trouble next time around.
|
1643 |
|
|
*/
|
1644 |
|
|
if (wait_for_ready(TIM_M) != TE_OK)
|
1645 |
|
|
return -EIO;
|
1646 |
|
|
switch (mode) {
|
1647 |
|
|
case READ:
|
1648 |
|
|
doing_read = YES;
|
1649 |
|
|
break;
|
1650 |
|
|
case WRITE:
|
1651 |
|
|
doing_write = YES;
|
1652 |
|
|
break;
|
1653 |
|
|
default:
|
1654 |
|
|
printk(TPQIC02_NAME ": requested unknown mode %d\n", mode);
|
1655 |
|
|
panic(TPQIC02_NAME ": invalid mode in start_dma()");
|
1656 |
|
|
}
|
1657 |
|
|
|
1658 |
|
|
} else if (is_exception()) {
|
1659 |
|
|
/* This is for Archive drives, to handle reads with 0 bytes
|
1660 |
|
|
* left for the last read request.
|
1661 |
|
|
*
|
1662 |
|
|
* ******** this also affects EOF/EOT handling! ************
|
1663 |
|
|
*/
|
1664 |
|
|
tpqputs(TPQD_ALWAYS, "detected exception in start_dma() while transfer in progress");
|
1665 |
|
|
status_error = YES;
|
1666 |
|
|
return TE_END;
|
1667 |
|
|
}
|
1668 |
|
|
|
1669 |
|
|
|
1670 |
|
|
status_expect_int = YES;
|
1671 |
|
|
|
1672 |
|
|
/* This assumes tape is already positioned, but these
|
1673 |
|
|
* semi-'intelligent' drives are unpredictable...
|
1674 |
|
|
*/
|
1675 |
|
|
TIMERON(TIM_M*2);
|
1676 |
|
|
|
1677 |
|
|
/* initiate first data block read from/write to the tape controller */
|
1678 |
|
|
|
1679 |
|
|
cli();
|
1680 |
|
|
dma_transfer();
|
1681 |
|
|
sti();
|
1682 |
|
|
|
1683 |
|
|
TPQPUTS("start_dma() end");
|
1684 |
|
|
return TE_OK;
|
1685 |
|
|
} /* start_dma */
|
1686 |
|
|
|
1687 |
|
|
|
1688 |
|
|
/* This cleans up after the dma transfer has completed
|
1689 |
|
|
* (or failed). If an exception occurred, a sense()
|
1690 |
|
|
* must be done. If the exception was caused by a FM,
|
1691 |
|
|
* sense() will set `status_eof_detected' and
|
1692 |
|
|
* `status_eom_detected', as required.
|
1693 |
|
|
*/
|
1694 |
|
|
static void end_dma(unsigned long * bytes_done)
|
1695 |
|
|
{
|
1696 |
|
|
int stat = TE_OK;
|
1697 |
|
|
|
1698 |
|
|
TIMEROFF;
|
1699 |
|
|
|
1700 |
|
|
TPQPUTS("end_dma() enter");
|
1701 |
|
|
|
1702 |
|
|
disable_dma(QIC02_TAPE_DMA);
|
1703 |
|
|
clear_dma_ff(QIC02_TAPE_DMA);
|
1704 |
|
|
|
1705 |
|
|
if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */
|
1706 |
|
|
outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT); /* back to normal */
|
1707 |
|
|
else if (QIC02_TAPE_IFC == ARCHIVE)
|
1708 |
|
|
outb_p(0, AR_RESET_DMA_PORT);
|
1709 |
|
|
else /* QIC02_TAPE_IFC == MOUNTAIN */ {
|
1710 |
|
|
/* Clear control bits, de-select ONLINE during tp_sense */
|
1711 |
|
|
ctlbits &= ~MTN_QIC02_CTL_ONLINE;
|
1712 |
|
|
}
|
1713 |
|
|
|
1714 |
|
|
stat = wait_for_ready(TIM_M);
|
1715 |
|
|
if (status_error || (stat!=TE_OK)) {
|
1716 |
|
|
tpqputs(TPQD_DMAX, "DMA transfer exception");
|
1717 |
|
|
stat = tp_sense((dma_mode==READ)? TP_WRP : 0);
|
1718 |
|
|
/* no return here -- got to clean up first! */
|
1719 |
|
|
} else /* if (QIC02_TAPE_IFC == MOUNTAIN) */ {
|
1720 |
|
|
outb_p(ctlbits, QIC02_CTL_PORT);
|
1721 |
|
|
}
|
1722 |
|
|
|
1723 |
|
|
if (QIC02_TAPE_IFC == MOUNTAIN)
|
1724 |
|
|
inb(MTN_R_DESELECT_DMA_PORT);
|
1725 |
|
|
|
1726 |
|
|
/* take the tape controller offline */
|
1727 |
|
|
|
1728 |
|
|
/* finish off DMA stuff */
|
1729 |
|
|
|
1730 |
|
|
|
1731 |
|
|
dma_mode = 0;
|
1732 |
|
|
/* Note: The drive is left on-line, ready for the next
|
1733 |
|
|
* data transfer.
|
1734 |
|
|
* If the next command to the drive does not continue
|
1735 |
|
|
* the pending cycle, it must do 2 sense()s first.
|
1736 |
|
|
*/
|
1737 |
|
|
|
1738 |
|
|
*bytes_done = dma_bytes_done;
|
1739 |
|
|
status_expect_int = NO;
|
1740 |
|
|
ioctl_status.mt_blkno += (dma_bytes_done / TAPE_BLKSIZE);
|
1741 |
|
|
|
1742 |
|
|
TPQPUTS("end_dma() exit");
|
1743 |
|
|
/*** could return stat here ***/
|
1744 |
|
|
} /* end_dma */
|
1745 |
|
|
|
1746 |
|
|
/*********** Below are the (public) OS-interface procedures ***********/
|
1747 |
|
|
|
1748 |
|
|
|
1749 |
|
|
/* qic02_tape_times_out() is called when a DMA transfer doesn't complete
|
1750 |
|
|
* quickly enough. Usually this means there is something seriously wrong
|
1751 |
|
|
* with the hardware/software, but it could just be that the controller
|
1752 |
|
|
* has decided to do a long rewind, just when I didn't expect it.
|
1753 |
|
|
* Just try again.
|
1754 |
|
|
*/
|
1755 |
|
|
static void qic02_tape_times_out(void)
|
1756 |
|
|
{
|
1757 |
|
|
printk("time-out in %s driver\n", TPQIC02_NAME);
|
1758 |
|
|
if ((status_cmd_pending>0) || dma_mode) {
|
1759 |
|
|
/* takes tooo long, shut it down */
|
1760 |
|
|
status_dead = YES;
|
1761 |
|
|
status_cmd_pending = 0;
|
1762 |
|
|
status_timer_on = NO;
|
1763 |
|
|
status_expect_int = NO;
|
1764 |
|
|
status_error = YES;
|
1765 |
|
|
if (dma_mode) {
|
1766 |
|
|
dma_mode = 0; /* signal end to read/write routine */
|
1767 |
|
|
wake_up(&qic02_tape_transfer);
|
1768 |
|
|
}
|
1769 |
|
|
}
|
1770 |
|
|
} /* qic02_tape_times_out */
|
1771 |
|
|
|
1772 |
|
|
/*
|
1773 |
|
|
* Interrupt handling:
|
1774 |
|
|
*
|
1775 |
|
|
* 1) Interrupt is generated iff at the end of
|
1776 |
|
|
* a 512-DMA-block transfer.
|
1777 |
|
|
* 2) EXCEPTION is not raised unless something
|
1778 |
|
|
* is wrong or EOT/FM is detected.
|
1779 |
|
|
* 3) FM EXCEPTION is set *after* the last byte has
|
1780 |
|
|
* been transferred by DMA. By the time the interrupt
|
1781 |
|
|
* is handled, the EXCEPTION may already be set.
|
1782 |
|
|
*
|
1783 |
|
|
* So,
|
1784 |
|
|
* 1) On EXCEPTION, assume data has been transferred, so
|
1785 |
|
|
* continue as usual, but set a flag to indicate the
|
1786 |
|
|
* exception was detected.
|
1787 |
|
|
* Do a sense status when the flag is found set.
|
1788 |
|
|
* 2) Do not attempt to continue a transfer after an exception.
|
1789 |
|
|
* [??? What about marginal blocks???????]
|
1790 |
|
|
*/
|
1791 |
|
|
|
1792 |
|
|
|
1793 |
|
|
/* qic02_tape_interrupt() is called when the tape controller completes
|
1794 |
|
|
* a DMA transfer.
|
1795 |
|
|
* We are not allowed to sleep here!
|
1796 |
|
|
*
|
1797 |
|
|
* Check if the transfer was successful, check if we need to transfer
|
1798 |
|
|
* more. If the buffer contains enough data/is empty enough, signal the
|
1799 |
|
|
* read/write() thread to copy to/from user space.
|
1800 |
|
|
* When we are finished, set flags to indicate end, disable timer.
|
1801 |
|
|
* NOTE: This *must* be fast!
|
1802 |
|
|
*/
|
1803 |
|
|
static void qic02_tape_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
1804 |
|
|
{
|
1805 |
|
|
int stat, r, i;
|
1806 |
|
|
|
1807 |
|
|
TIMEROFF;
|
1808 |
|
|
|
1809 |
|
|
if (status_expect_int) {
|
1810 |
|
|
#ifdef WANT_EXTRA_FULL_DEBUGGING
|
1811 |
|
|
if (TP_DIAGS(current_tape_dev))
|
1812 |
|
|
printk("@");
|
1813 |
|
|
#endif
|
1814 |
|
|
stat = inb(QIC02_STAT_PORT); /* Knock, knock */
|
1815 |
|
|
if (QIC02_TAPE_IFC == ARCHIVE) { /* "Who's there?" */
|
1816 |
|
|
if (((stat & (AR_STAT_DMADONE)) == 0) &&
|
1817 |
|
|
((stat & (QIC02_STAT_EXCEPTION)) != 0)) {
|
1818 |
|
|
TIMERCONT;
|
1819 |
|
|
return; /* "Linux with IRQ sharing" */
|
1820 |
|
|
}
|
1821 |
|
|
}
|
1822 |
|
|
|
1823 |
|
|
if ((stat & QIC02_STAT_EXCEPTION) == 0) { /* exception occurred */
|
1824 |
|
|
/* Possible causes for an exception during a transfer:
|
1825 |
|
|
* - during a write-cycle: end of tape (EW) hole detected.
|
1826 |
|
|
* - during a read-cycle: filemark or EOD detected.
|
1827 |
|
|
* - something went wrong
|
1828 |
|
|
* So don't continue with the next block.
|
1829 |
|
|
*/
|
1830 |
|
|
tpqputs(TPQD_ALWAYS, "isr: exception on tape controller");
|
1831 |
|
|
printk(" status %02x\n", stat);
|
1832 |
|
|
status_error = TE_EX;
|
1833 |
|
|
|
1834 |
|
|
dma_bytes_done += TAPE_BLKSIZE;
|
1835 |
|
|
|
1836 |
|
|
dma_mode = 0; /* wake up rw() */
|
1837 |
|
|
status_expect_int = NO;
|
1838 |
|
|
wake_up(&qic02_tape_transfer);
|
1839 |
|
|
return;
|
1840 |
|
|
}
|
1841 |
|
|
/* return if tape controller not ready, or
|
1842 |
|
|
* if dma channel hasn't finished last byte yet.
|
1843 |
|
|
*/
|
1844 |
|
|
r = 0;
|
1845 |
|
|
/* Skip next ready check for Archive controller because
|
1846 |
|
|
* it may be busy reading ahead. Weird. --hhb
|
1847 |
|
|
*/
|
1848 |
|
|
if (QIC02_TAPE_IFC == WANGTEK) /* I think this is a drive-dependency, not IFC -- hhb */
|
1849 |
|
|
if (stat & QIC02_STAT_READY) { /* not ready */
|
1850 |
|
|
tpqputs(TPQD_ALWAYS, "isr: ? Tape controller not ready");
|
1851 |
|
|
r = 1;
|
1852 |
|
|
}
|
1853 |
|
|
|
1854 |
|
|
if ( (i = get_dma_residue(QIC02_TAPE_DMA)) != 0 ) {
|
1855 |
|
|
printk(TPQIC02_NAME ": dma_residue == %x !!!\n", i);
|
1856 |
|
|
r = 1; /* big trouble, but can't do much about it... */
|
1857 |
|
|
}
|
1858 |
|
|
|
1859 |
|
|
if (r)
|
1860 |
|
|
return;
|
1861 |
|
|
|
1862 |
|
|
/* finish DMA cycle */
|
1863 |
|
|
|
1864 |
|
|
/* no errors detected, continue */
|
1865 |
|
|
dma_bytes_done += TAPE_BLKSIZE;
|
1866 |
|
|
if (dma_bytes_done >= dma_bytes_todo) {
|
1867 |
|
|
/* finished! Wakeup rw() */
|
1868 |
|
|
dma_mode = 0;
|
1869 |
|
|
status_expect_int = NO;
|
1870 |
|
|
TPQPUTS("isr: dma_bytes_done");
|
1871 |
|
|
wake_up(&qic02_tape_transfer);
|
1872 |
|
|
} else {
|
1873 |
|
|
/* start next transfer, account for track-switching time */
|
1874 |
|
|
timer_table[QIC02_TAPE_TIMER].expires = jiffies + 6*HZ;
|
1875 |
|
|
dma_transfer();
|
1876 |
|
|
}
|
1877 |
|
|
} else {
|
1878 |
|
|
printk(TPQIC02_NAME ": Unexpected interrupt, stat == %x\n",
|
1879 |
|
|
inb(QIC02_STAT_PORT));
|
1880 |
|
|
}
|
1881 |
|
|
} /* qic02_tape_interrupt */
|
1882 |
|
|
|
1883 |
|
|
|
1884 |
|
|
static int qic02_tape_lseek(struct inode * inode, struct file * file, off_t offset, int origin)
|
1885 |
|
|
{
|
1886 |
|
|
return -EINVAL; /* not supported */
|
1887 |
|
|
} /* qic02_tape_lseek */
|
1888 |
|
|
|
1889 |
|
|
|
1890 |
|
|
/* read/write routines:
|
1891 |
|
|
* This code copies between a kernel buffer and a user buffer. The
|
1892 |
|
|
* actual data transfer is done using DMA and interrupts. Time-outs
|
1893 |
|
|
* are also used.
|
1894 |
|
|
*
|
1895 |
|
|
* When a filemark is read, we return '0 bytes read' and continue with the
|
1896 |
|
|
* next file after that.
|
1897 |
|
|
* When EOM is read, we return '0 bytes read' twice.
|
1898 |
|
|
* When the EOT marker is detected on writes, '0 bytes read' should be
|
1899 |
|
|
* returned twice. If user program does a MTNOP after that, 2 additional
|
1900 |
|
|
* blocks may be written. ------- FIXME: Implement this correctly *************************************************
|
1901 |
|
|
*
|
1902 |
|
|
* Only read/writes in multiples of 512 bytes are accepted.
|
1903 |
|
|
* When no bytes are available, we sleep() until they are. The controller will
|
1904 |
|
|
* generate an interrupt, and we (should) get a wake_up() call.
|
1905 |
|
|
*
|
1906 |
|
|
* Simple buffering is used. User program should ensure that a large enough
|
1907 |
|
|
* buffer is used. Usually the drive does some buffering as well (something
|
1908 |
|
|
* like 4k or so).
|
1909 |
|
|
*
|
1910 |
|
|
* Scott S. Bertilson suggested to continue filling the user buffer, rather
|
1911 |
|
|
* than waste time on a context switch, when the kernel buffer fills up.
|
1912 |
|
|
*/
|
1913 |
|
|
|
1914 |
|
|
/*
|
1915 |
|
|
* Problem: tar(1) doesn't always read the entire file. Sometimes the entire file
|
1916 |
|
|
* has been read, but the EOF token is never returned to tar(1), simply because
|
1917 |
|
|
* tar(1) knows it has already read all of the data it needs. So we must use
|
1918 |
|
|
* open/release to reset the `reported_read_eof' flag. If we don't, the next read
|
1919 |
|
|
* request would return the EOF flag for the previous file.
|
1920 |
|
|
*/
|
1921 |
|
|
|
1922 |
|
|
static int qic02_tape_read(struct inode * inode, struct file * filp, char * buf, int count)
|
1923 |
|
|
{
|
1924 |
|
|
int error;
|
1925 |
|
|
kdev_t dev = inode->i_rdev;
|
1926 |
|
|
unsigned short flags = filp->f_flags;
|
1927 |
|
|
unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
|
1928 |
|
|
int stat;
|
1929 |
|
|
|
1930 |
|
|
if (status_zombie==YES) {
|
1931 |
|
|
tpqputs(TPQD_ALWAYS, "configs not set");
|
1932 |
|
|
return -ENXIO;
|
1933 |
|
|
}
|
1934 |
|
|
|
1935 |
|
|
if (TP_DIAGS(current_tape_dev))
|
1936 |
|
|
/* can't print a ``long long'' (for filp->f_pos), so chop it */
|
1937 |
|
|
printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
|
1938 |
|
|
MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
|
1939 |
|
|
|
1940 |
|
|
if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */
|
1941 |
|
|
tpqputs(TPQD_BLKSZ, "Wrong block size");
|
1942 |
|
|
return -EINVAL;
|
1943 |
|
|
}
|
1944 |
|
|
|
1945 |
|
|
/* Just assume everything is ok. Controller will scream if not. */
|
1946 |
|
|
|
1947 |
|
|
if (status_bytes_wr) /* Once written, no more reads, 'till after WFM. */
|
1948 |
|
|
return -EACCES;
|
1949 |
|
|
|
1950 |
|
|
|
1951 |
|
|
/* Make sure buffer is safe to write into. */
|
1952 |
|
|
error = verify_area(VERIFY_WRITE, buf, count);
|
1953 |
|
|
if (error)
|
1954 |
|
|
return error;
|
1955 |
|
|
|
1956 |
|
|
/* This is rather ugly because it has to implement a finite state
|
1957 |
|
|
* machine in order to handle the EOF situations properly.
|
1958 |
|
|
*/
|
1959 |
|
|
while (count>=0) {
|
1960 |
|
|
bytes_done = 0;
|
1961 |
|
|
/* see how much fits in the kernel buffer */
|
1962 |
|
|
bytes_todo = TPQBUF_SIZE;
|
1963 |
|
|
if (bytes_todo>count)
|
1964 |
|
|
bytes_todo = count;
|
1965 |
|
|
|
1966 |
|
|
/* Must ensure that user program sees exactly one EOF token (==0) */
|
1967 |
|
|
if (return_read_eof==YES) {
|
1968 |
|
|
if (TPQDBG(DEBUG))
|
1969 |
|
|
printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%lu\n", return_read_eof, reported_read_eof, total_bytes_done);
|
1970 |
|
|
|
1971 |
|
|
if (reported_read_eof==NO) {
|
1972 |
|
|
/* have not yet returned EOF to user program */
|
1973 |
|
|
if (total_bytes_done>0) {
|
1974 |
|
|
return total_bytes_done; /* next time return EOF */
|
1975 |
|
|
} else {
|
1976 |
|
|
reported_read_eof = YES; /* move on next time */
|
1977 |
|
|
return 0; /* return EOF */
|
1978 |
|
|
}
|
1979 |
|
|
} else {
|
1980 |
|
|
/* Application program has already received EOF
|
1981 |
|
|
* (above), now continue with next file on tape,
|
1982 |
|
|
* if possible.
|
1983 |
|
|
* When the FM is reached, EXCEPTION is set,
|
1984 |
|
|
* causing a sense(). Subsequent read/writes will
|
1985 |
|
|
* continue after the FM.
|
1986 |
|
|
*/
|
1987 |
|
|
/*********** ?????????? this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/
|
1988 |
|
|
if (status_eom_detected)
|
1989 |
|
|
/* If EOM, nothing left to read, so keep returning EOFs.
|
1990 |
|
|
*** should probably set some flag to avoid clearing
|
1991 |
|
|
*** status_eom_detected through ioctls or something
|
1992 |
|
|
*/
|
1993 |
|
|
return 0;
|
1994 |
|
|
else {
|
1995 |
|
|
/* just eof, there may be more files ahead... */
|
1996 |
|
|
return_read_eof = NO;
|
1997 |
|
|
reported_read_eof = NO;
|
1998 |
|
|
status_eof_detected = NO; /* reset this too */
|
1999 |
|
|
/*fall through*/
|
2000 |
|
|
}
|
2001 |
|
|
}
|
2002 |
|
|
}
|
2003 |
|
|
|
2004 |
|
|
/*****************************/
|
2005 |
|
|
if (bytes_todo==0)
|
2006 |
|
|
return total_bytes_done;
|
2007 |
|
|
|
2008 |
|
|
if (bytes_todo>0) {
|
2009 |
|
|
/* start reading data */
|
2010 |
|
|
if (is_exception()) /****************************************/
|
2011 |
|
|
tpqputs(TPQD_DMAX, "is_exception() before start_dma()!");
|
2012 |
|
|
/******************************************************************
|
2013 |
|
|
***** if start_dma() fails because the head is positioned 0 bytes
|
2014 |
|
|
***** before the FM, (causing EXCEPTION to be set) return_read_eof should
|
2015 |
|
|
***** be set to YES, and we should return total_bytes_done, rather than -ENXIO.
|
2016 |
|
|
***** The app should recognize this as an EOF condition.
|
2017 |
|
|
***************************************************************************/
|
2018 |
|
|
stat = start_dma(READ, bytes_todo);
|
2019 |
|
|
if (stat == TE_OK) {
|
2020 |
|
|
/* Wait for transfer to complete, interrupt should wake us */
|
2021 |
|
|
while (dma_mode != 0) {
|
2022 |
|
|
sleep_on(&qic02_tape_transfer);
|
2023 |
|
|
}
|
2024 |
|
|
if (status_error)
|
2025 |
|
|
return_read_eof = YES;
|
2026 |
|
|
} else if (stat != TE_END) {
|
2027 |
|
|
/* should do sense() on error here */
|
2028 |
|
|
#if 0
|
2029 |
|
|
return -ENXIO;
|
2030 |
|
|
#else
|
2031 |
|
|
printk("Trouble: stat==%02x\n", stat);
|
2032 |
|
|
return_read_eof = YES;
|
2033 |
|
|
/*************** check EOF/EOT handling!!!!!! **/
|
2034 |
|
|
#endif
|
2035 |
|
|
}
|
2036 |
|
|
end_dma(&bytes_done);
|
2037 |
|
|
if (bytes_done>bytes_todo) {
|
2038 |
|
|
tpqputs(TPQD_ALWAYS, "read: Oops, read more bytes than requested");
|
2039 |
|
|
return -EIO;
|
2040 |
|
|
}
|
2041 |
|
|
/* copy buffer to user-space in one go */
|
2042 |
|
|
if (bytes_done>0)
|
2043 |
|
|
memcpy_tofs( (void *) buf, (void *) buffaddr, bytes_done);
|
2044 |
|
|
#if 1
|
2045 |
|
|
/* Checks Ton's patch below */
|
2046 |
|
|
if ((return_read_eof == NO) && (status_eof_detected == YES)) {
|
2047 |
|
|
printk(TPQIC02_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n", return_read_eof);
|
2048 |
|
|
}
|
2049 |
|
|
#endif
|
2050 |
|
|
if ((bytes_todo != bytes_done) || (status_eof_detected == YES))
|
2051 |
|
|
/* EOF or EOM detected. return EOF next time. */
|
2052 |
|
|
return_read_eof = YES;
|
2053 |
|
|
} /* else: ignore read request for 0 bytes */
|
2054 |
|
|
|
2055 |
|
|
if (bytes_done>0) {
|
2056 |
|
|
status_bytes_rd = YES;
|
2057 |
|
|
buf += bytes_done;
|
2058 |
|
|
filp->f_pos += bytes_done;
|
2059 |
|
|
total_bytes_done += bytes_done;
|
2060 |
|
|
count -= bytes_done;
|
2061 |
|
|
}
|
2062 |
|
|
}
|
2063 |
|
|
tpqputs(TPQD_ALWAYS, "read request for <0 bytes");
|
2064 |
|
|
return -EINVAL;
|
2065 |
|
|
} /* qic02_tape_read */
|
2066 |
|
|
|
2067 |
|
|
|
2068 |
|
|
|
2069 |
|
|
/* The drive detects near-EOT by means of the holes in the tape.
|
2070 |
|
|
* When the holes are detected, there is some space left. The drive
|
2071 |
|
|
* reports this as a TP_EOM exception. After clearing the exception,
|
2072 |
|
|
* the drive should accept two extra blocks.
|
2073 |
|
|
*
|
2074 |
|
|
* It seems there are some archiver programs that would like to use the
|
2075 |
|
|
* extra space for writing a continuation marker. The driver should return
|
2076 |
|
|
* end-of-file to the user program on writes, when the holes are detected.
|
2077 |
|
|
* If the user-program wants to use the extra space, it should use the
|
2078 |
|
|
* MTNOP ioctl() to get the generic status register and may then continue
|
2079 |
|
|
* writing (max 1kB). ----------- doesn't work yet...............
|
2080 |
|
|
*
|
2081 |
|
|
* EOF behaviour on writes:
|
2082 |
|
|
* If there is enough room, write all of the data.
|
2083 |
|
|
* If there is insufficient room, write as much as will fit and
|
2084 |
|
|
* return the amount written. If the requested amount differs from the
|
2085 |
|
|
* written amount, the application program should recognize that as the
|
2086 |
|
|
* end of file. Subsequent writes will return -ENOSPC.
|
2087 |
|
|
* Unless the minor bits specify a rewind-on-close, the tape will not
|
2088 |
|
|
* be rewound when it is full. The user-program should do that, if desired.
|
2089 |
|
|
* If the driver were to do that automatically, a user-program could be
|
2090 |
|
|
* confused about the EOT/BOT condition after re-opening the tape device.
|
2091 |
|
|
*
|
2092 |
|
|
* Multiple volume support: Tar closes the tape device before prompting for
|
2093 |
|
|
* the next tape. The user may then insert a new tape and tar will open the
|
2094 |
|
|
* tape device again. The driver will detect an exception status in (No Cartridge)
|
2095 |
|
|
* and force a rewind. After that tar may continue writing.
|
2096 |
|
|
*/
|
2097 |
|
|
static int qic02_tape_write(struct inode * inode, struct file * filp, const char * buf, int count)
|
2098 |
|
|
{
|
2099 |
|
|
int error;
|
2100 |
|
|
kdev_t dev = inode->i_rdev;
|
2101 |
|
|
unsigned short flags = filp->f_flags;
|
2102 |
|
|
unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
|
2103 |
|
|
|
2104 |
|
|
if (status_zombie==YES) {
|
2105 |
|
|
tpqputs(TPQD_ALWAYS, "configs not set");
|
2106 |
|
|
return -ENXIO;
|
2107 |
|
|
}
|
2108 |
|
|
|
2109 |
|
|
if (TP_DIAGS(current_tape_dev))
|
2110 |
|
|
/* can't print a ``long long'' (for filp->f_pos), so chop it */
|
2111 |
|
|
printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
|
2112 |
|
|
MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
|
2113 |
|
|
|
2114 |
|
|
if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */
|
2115 |
|
|
tpqputs(TPQD_BLKSZ, "Wrong block size");
|
2116 |
|
|
return -EINVAL;
|
2117 |
|
|
}
|
2118 |
|
|
|
2119 |
|
|
if (mode_access==READ) {
|
2120 |
|
|
tpqputs(TPQD_ALWAYS, "Not in write mode");
|
2121 |
|
|
return -EACCES;
|
2122 |
|
|
}
|
2123 |
|
|
|
2124 |
|
|
/* open() does a sense() and we can assume the tape isn't changed
|
2125 |
|
|
* between open() and release(), so the tperror.exs bits will still
|
2126 |
|
|
* be valid.
|
2127 |
|
|
*/
|
2128 |
|
|
if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {
|
2129 |
|
|
tpqputs(TPQD_ALWAYS, "Cartridge is write-protected.");
|
2130 |
|
|
return -EACCES; /* don't even try when write protected */
|
2131 |
|
|
}
|
2132 |
|
|
|
2133 |
|
|
/* Make sure buffer is safe to read from. */
|
2134 |
|
|
error = verify_area(VERIFY_READ, buf, count);
|
2135 |
|
|
if (error)
|
2136 |
|
|
return error;
|
2137 |
|
|
|
2138 |
|
|
if (doing_read == YES)
|
2139 |
|
|
terminate_read(0);
|
2140 |
|
|
|
2141 |
|
|
while (count>=0) {
|
2142 |
|
|
/* see how much fits in the kernel buffer */
|
2143 |
|
|
bytes_done = 0;
|
2144 |
|
|
bytes_todo = TPQBUF_SIZE;
|
2145 |
|
|
if (bytes_todo>count)
|
2146 |
|
|
bytes_todo = count;
|
2147 |
|
|
|
2148 |
|
|
if (return_write_eof == YES) {
|
2149 |
|
|
/* return_write_eof should be reset on reverse tape movements. */
|
2150 |
|
|
|
2151 |
|
|
if (reported_write_eof==NO) {
|
2152 |
|
|
if (bytes_todo>0) {
|
2153 |
|
|
tpqputs(TPQD_ALWAYS, "partial write");
|
2154 |
|
|
/* partial write signals EOF to user program */
|
2155 |
|
|
}
|
2156 |
|
|
reported_write_eof = YES;
|
2157 |
|
|
return total_bytes_done;
|
2158 |
|
|
} else {
|
2159 |
|
|
return -ENOSPC; /* return error */
|
2160 |
|
|
}
|
2161 |
|
|
}
|
2162 |
|
|
|
2163 |
|
|
/* Quit when done. */
|
2164 |
|
|
if (bytes_todo==0)
|
2165 |
|
|
return total_bytes_done;
|
2166 |
|
|
|
2167 |
|
|
|
2168 |
|
|
/* copy from user to DMA buffer and initiate transfer. */
|
2169 |
|
|
if (bytes_todo>0) {
|
2170 |
|
|
memcpy_fromfs( (void *) buffaddr, (const void *) buf, bytes_todo);
|
2171 |
|
|
|
2172 |
|
|
/****************** similar problem with read() at FM could happen here at EOT.
|
2173 |
|
|
******************/
|
2174 |
|
|
|
2175 |
|
|
/***** if at EOT, 0 bytes can be written. start_dma() will
|
2176 |
|
|
***** fail and write() will return ENXIO error
|
2177 |
|
|
*****/
|
2178 |
|
|
if (start_dma(WRITE, bytes_todo) != TE_OK) {
|
2179 |
|
|
tpqputs(TPQD_ALWAYS, "write: start_dma() failed");
|
2180 |
|
|
/* should do sense() on error here */
|
2181 |
|
|
return -ENXIO; /*********** FIXTHIS **************/
|
2182 |
|
|
}
|
2183 |
|
|
|
2184 |
|
|
/* Wait for write to complete, interrupt should wake us. */
|
2185 |
|
|
while ((status_error == 0) && (dma_mode != 0)) {
|
2186 |
|
|
sleep_on(&qic02_tape_transfer);
|
2187 |
|
|
}
|
2188 |
|
|
|
2189 |
|
|
end_dma(&bytes_done);
|
2190 |
|
|
if (bytes_done>bytes_todo) {
|
2191 |
|
|
tpqputs(TPQD_ALWAYS, "write: Oops, wrote more bytes than requested");
|
2192 |
|
|
return -EIO;
|
2193 |
|
|
}
|
2194 |
|
|
/* If the dma-transfer was aborted because of an exception,
|
2195 |
|
|
* status_error will have been set in the interrupt handler.
|
2196 |
|
|
* Then end_dma() will do a sense().
|
2197 |
|
|
* If the exception was EXC_EOM, the EW-hole was encountered
|
2198 |
|
|
* and two more blocks could be written. For the time being we'll
|
2199 |
|
|
* just consider this to be the EOT.
|
2200 |
|
|
* Otherwise, something Bad happened, such as the maximum number
|
2201 |
|
|
* of block-rewrites was exceeded. [e.g. A very bad spot on tape was
|
2202 |
|
|
* encountered. Normally short dropouts are compensated for by
|
2203 |
|
|
* rewriting the block in error, up to 16 times. I'm not sure
|
2204 |
|
|
* QIC-24 drives can do this.]
|
2205 |
|
|
*/
|
2206 |
|
|
if (status_error) {
|
2207 |
|
|
if (status_eom_detected == YES) {
|
2208 |
|
|
tpqputs(TPQD_ALWAYS, "write: EW detected");
|
2209 |
|
|
return_write_eof = YES;
|
2210 |
|
|
} else {
|
2211 |
|
|
/* probably EXC_RWA */
|
2212 |
|
|
tpqputs(TPQD_ALWAYS, "write: dma: error in writing");
|
2213 |
|
|
return -EIO;
|
2214 |
|
|
}
|
2215 |
|
|
}
|
2216 |
|
|
if (bytes_todo != bytes_done)
|
2217 |
|
|
/* EOF or EOM detected. return EOT next time. */
|
2218 |
|
|
return_write_eof = YES;
|
2219 |
|
|
}
|
2220 |
|
|
/* else: ignore write request for 0 bytes. */
|
2221 |
|
|
|
2222 |
|
|
if (bytes_done>0) {
|
2223 |
|
|
status_bytes_wr = YES;
|
2224 |
|
|
buf += bytes_done;
|
2225 |
|
|
filp->f_pos += bytes_done;
|
2226 |
|
|
total_bytes_done += bytes_done;
|
2227 |
|
|
count -= bytes_done;
|
2228 |
|
|
}
|
2229 |
|
|
}
|
2230 |
|
|
tpqputs(TPQD_ALWAYS, "write request for <0 bytes");
|
2231 |
|
|
if (TPQDBG(DEBUG))
|
2232 |
|
|
printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %lx, count %x\n", status_bytes_wr, buf, total_bytes_done, count);
|
2233 |
|
|
return -EINVAL;
|
2234 |
|
|
} /* qic02_tape_write */
|
2235 |
|
|
|
2236 |
|
|
|
2237 |
|
|
|
2238 |
|
|
/* qic02_tape_open()
|
2239 |
|
|
* We allow the device to be opened, even if it is marked 'dead' because
|
2240 |
|
|
* we want to be able to reset the tape device without rebooting.
|
2241 |
|
|
* Only one open tape file at a time, except when minor=255.
|
2242 |
|
|
* Minor 255 is only allowed for resetting and always returns <0.
|
2243 |
|
|
*
|
2244 |
|
|
* The density command is only allowed when TP_BOM is set. Thus, remember
|
2245 |
|
|
* the most recently used minor bits. When they are different from the
|
2246 |
|
|
* remembered values, rewind the tape and set the required density.
|
2247 |
|
|
* Don't rewind if the minor bits specify density 0.
|
2248 |
|
|
*/
|
2249 |
|
|
static int qic02_tape_open(struct inode * inode, struct file * filp)
|
2250 |
|
|
{
|
2251 |
|
|
kdev_t dev = inode->i_rdev;
|
2252 |
|
|
unsigned short flags = filp->f_flags;
|
2253 |
|
|
unsigned short dens = 0;
|
2254 |
|
|
int s;
|
2255 |
|
|
|
2256 |
|
|
|
2257 |
|
|
if (TP_DIAGS(dev)) {
|
2258 |
|
|
printk("qic02_tape_open: dev=%s, flags=%x ",
|
2259 |
|
|
kdevname(dev), flags);
|
2260 |
|
|
}
|
2261 |
|
|
|
2262 |
|
|
if (MINOR(dev)==255) /* special case for resetting */
|
2263 |
|
|
if (suser())
|
2264 |
|
|
return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO;
|
2265 |
|
|
else
|
2266 |
|
|
return -EPERM;
|
2267 |
|
|
|
2268 |
|
|
if (status_dead==YES)
|
2269 |
|
|
/* Allow `mt reset' ioctl() even when already open()ed. */
|
2270 |
|
|
return 0;
|
2271 |
|
|
|
2272 |
|
|
/* Only one at a time from here on... */
|
2273 |
|
|
if (filp->f_count>1) { /* filp->f_count==1 for the first open() */
|
2274 |
|
|
return -EBUSY;
|
2275 |
|
|
}
|
2276 |
|
|
|
2277 |
|
|
if (status_zombie==YES)
|
2278 |
|
|
/* no irq/dma/port stuff allocated yet, no reset done
|
2279 |
|
|
* yet, so return until MTSETCONFIG has been done.
|
2280 |
|
|
*/
|
2281 |
|
|
return 0;
|
2282 |
|
|
|
2283 |
|
|
status_bytes_rd = NO;
|
2284 |
|
|
status_bytes_wr = NO;
|
2285 |
|
|
|
2286 |
|
|
return_read_eof = NO; /********????????????????*****/
|
2287 |
|
|
return_write_eof = (status_eot_detected)? YES : NO;
|
2288 |
|
|
|
2289 |
|
|
/* Clear this in case user app close()d before reading EOF token */
|
2290 |
|
|
status_eof_detected = NO;
|
2291 |
|
|
|
2292 |
|
|
reported_read_eof = NO;
|
2293 |
|
|
reported_write_eof = NO;
|
2294 |
|
|
|
2295 |
|
|
|
2296 |
|
|
switch (flags & O_ACCMODE) {
|
2297 |
|
|
case O_RDONLY:
|
2298 |
|
|
mode_access = READ;
|
2299 |
|
|
break;
|
2300 |
|
|
case O_WRONLY: /* Fallthru... Strictly speaking this is not correct... */
|
2301 |
|
|
case O_RDWR: /* Reads are allowed as long as nothing is written */
|
2302 |
|
|
mode_access = WRITE;
|
2303 |
|
|
break;
|
2304 |
|
|
}
|
2305 |
|
|
|
2306 |
|
|
/* This is to avoid tape-changed problems (TP_CNI exception).
|
2307 |
|
|
*
|
2308 |
|
|
* Since removing the cartridge will not raise an exception,
|
2309 |
|
|
* we always do a tp_sense() to make sure we have the proper
|
2310 |
|
|
* CNI status, the 2150L may need an additional sense.... - Eddy
|
2311 |
|
|
*/
|
2312 |
|
|
s = tp_sense(TP_WRP|TP_EOM|TP_BOM|TP_CNI|TP_EOR);
|
2313 |
|
|
|
2314 |
|
|
if (s == TE_OK)
|
2315 |
|
|
/* Try to clear cartridge-changed status for Archive-2150L */
|
2316 |
|
|
if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI))
|
2317 |
|
|
s = tp_sense(TP_WRP|TP_EOM|TP_BOM|TP_CNI|TP_EOR);
|
2318 |
|
|
|
2319 |
|
|
if (s != TE_OK) {
|
2320 |
|
|
tpqputs(TPQD_ALWAYS, "open: sense() failed");
|
2321 |
|
|
return -EIO;
|
2322 |
|
|
}
|
2323 |
|
|
|
2324 |
|
|
/* exception bits should be up-to-date now, so check for
|
2325 |
|
|
* tape presence and exit if absent.
|
2326 |
|
|
* Even `mt stat' will fail without a tape.
|
2327 |
|
|
*/
|
2328 |
|
|
if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) {
|
2329 |
|
|
tpqputs(TPQD_ALWAYS, "No tape present.");
|
2330 |
|
|
return -EIO;
|
2331 |
|
|
}
|
2332 |
|
|
|
2333 |
|
|
/* At this point we can assume that a tape is present and
|
2334 |
|
|
* that it will remain present until release() is called.
|
2335 |
|
|
*/
|
2336 |
|
|
|
2337 |
|
|
/* not allowed to do QCMD_DENS_* unless tape is rewound */
|
2338 |
|
|
if ((TP_DENS(dev)!=0) && (TP_DENS(current_tape_dev) != TP_DENS(dev))) {
|
2339 |
|
|
/* force rewind if minor bits have changed,
|
2340 |
|
|
* i.e. user wants to use tape in different format.
|
2341 |
|
|
* [assuming single drive operation]
|
2342 |
|
|
*/
|
2343 |
|
|
if (TP_HAVE_DENS) {
|
2344 |
|
|
tpqputs(TPQD_REWIND, "Density minor bits have changed. Forcing rewind.");
|
2345 |
|
|
need_rewind = YES;
|
2346 |
|
|
}
|
2347 |
|
|
} else {
|
2348 |
|
|
/* density bits still the same, but TP_DIAGS bit
|
2349 |
|
|
* may have changed.
|
2350 |
|
|
*/
|
2351 |
|
|
current_tape_dev = dev;
|
2352 |
|
|
}
|
2353 |
|
|
|
2354 |
|
|
if (need_rewind == YES) { /***************** CHECK THIS!!!!!!!! **********/
|
2355 |
|
|
s = do_qic_cmd(QCMD_REWIND, TIM_R);
|
2356 |
|
|
if (s != 0) {
|
2357 |
|
|
tpqputs(TPQD_ALWAYS, "open: rewind failed");
|
2358 |
|
|
return -EIO;
|
2359 |
|
|
}
|
2360 |
|
|
}
|
2361 |
|
|
|
2362 |
|
|
|
2363 |
|
|
/* Note: After a reset command, the controller will rewind the tape
|
2364 |
|
|
* just before performing any tape movement operation! ************ SO SET need_rewind flag!!!!!
|
2365 |
|
|
*/
|
2366 |
|
|
if (status_dead==YES) {
|
2367 |
|
|
tpqputs(TPQD_ALWAYS, "open: tape dead, attempting reset");
|
2368 |
|
|
if (tape_reset(1)!=TE_OK) {
|
2369 |
|
|
return -ENXIO;
|
2370 |
|
|
} else {
|
2371 |
|
|
status_dead = NO;
|
2372 |
|
|
if (tp_sense(~(TP_ST1|TP_ILL)) != TE_OK) {
|
2373 |
|
|
tpqputs(TPQD_ALWAYS, "open: tp_sense() failed\n");
|
2374 |
|
|
status_dead = YES; /* try reset next time */
|
2375 |
|
|
return -EIO;
|
2376 |
|
|
}
|
2377 |
|
|
}
|
2378 |
|
|
}
|
2379 |
|
|
|
2380 |
|
|
/* things should be ok, once we get here */
|
2381 |
|
|
|
2382 |
|
|
|
2383 |
|
|
/* set density: only allowed when TP_BOM status bit is set,
|
2384 |
|
|
* so we must have done a rewind by now. If not, just skip over.
|
2385 |
|
|
* Only give set density command when minor bits have changed.
|
2386 |
|
|
*/
|
2387 |
|
|
if (TP_DENS(current_tape_dev) == TP_DENS(dev) )
|
2388 |
|
|
return 0;
|
2389 |
|
|
|
2390 |
|
|
current_tape_dev = dev;
|
2391 |
|
|
need_rewind = NO;
|
2392 |
|
|
if (TP_HAVE_DENS)
|
2393 |
|
|
dens = TP_DENS(dev);
|
2394 |
|
|
|
2395 |
|
|
if (dens < sizeof(format_names)/sizeof(char *))
|
2396 |
|
|
printk(TPQIC02_NAME ": format: %s%s\n", (dens!=0)? "QIC-" : "", format_names[dens]);
|
2397 |
|
|
else
|
2398 |
|
|
tpqputs(TPQD_REWIND, "Wait for retensioning...");
|
2399 |
|
|
|
2400 |
|
|
switch (TP_DENS(dev)) {
|
2401 |
|
|
case 0: /* Minor 0 is for drives without set-density support */
|
2402 |
|
|
s = 0;
|
2403 |
|
|
break;
|
2404 |
|
|
case 1:
|
2405 |
|
|
s = do_qic_cmd(QCMD_DENS_11, TIM_S);
|
2406 |
|
|
break;
|
2407 |
|
|
case 2:
|
2408 |
|
|
s = do_qic_cmd(QCMD_DENS_24, TIM_S);
|
2409 |
|
|
break;
|
2410 |
|
|
case 3:
|
2411 |
|
|
s = do_qic_cmd(QCMD_DENS_120, TIM_S);
|
2412 |
|
|
break;
|
2413 |
|
|
case 4:
|
2414 |
|
|
s = do_qic_cmd(QCMD_DENS_150, TIM_S);
|
2415 |
|
|
break;
|
2416 |
|
|
case 5:
|
2417 |
|
|
s = do_qic_cmd(QCMD_DENS_300, TIM_S);
|
2418 |
|
|
break;
|
2419 |
|
|
case 6:
|
2420 |
|
|
s = do_qic_cmd(QCMD_DENS_600, TIM_S);
|
2421 |
|
|
break;
|
2422 |
|
|
default: /* otherwise do a retension before anything else */
|
2423 |
|
|
s = do_qic_cmd(QCMD_RETEN, TIM_R);
|
2424 |
|
|
}
|
2425 |
|
|
if (s != 0) {
|
2426 |
|
|
status_dead = YES; /* force reset */
|
2427 |
|
|
current_tape_dev = 0; /* earlier 0xff80 */
|
2428 |
|
|
return -EIO;
|
2429 |
|
|
}
|
2430 |
|
|
|
2431 |
|
|
return 0;
|
2432 |
|
|
} /* qic02_tape_open */
|
2433 |
|
|
|
2434 |
|
|
|
2435 |
|
|
static void qic02_tape_release(struct inode * inode, struct file * filp)
|
2436 |
|
|
{
|
2437 |
|
|
kdev_t dev = inode->i_rdev;
|
2438 |
|
|
|
2439 |
|
|
if (TP_DIAGS(dev))
|
2440 |
|
|
printk("qic02_tape_release: dev=%s\n",
|
2441 |
|
|
kdevname(dev));
|
2442 |
|
|
|
2443 |
|
|
if (status_zombie==YES) /* don't rewind in zombie mode */
|
2444 |
|
|
return;
|
2445 |
|
|
|
2446 |
|
|
/* Terminate any pending write cycle. Terminating the read-cycle
|
2447 |
|
|
* is delayed until it is required to do so for a new command.
|
2448 |
|
|
*/
|
2449 |
|
|
terminate_write(-1);
|
2450 |
|
|
|
2451 |
|
|
if (status_dead==YES)
|
2452 |
|
|
tpqputs(TPQD_ALWAYS, "release: device dead!?");
|
2453 |
|
|
|
2454 |
|
|
/* Rewind only if minor number requires it AND
|
2455 |
|
|
* read/writes have been done. ************* IS THIS CORRECT??????????
|
2456 |
|
|
*/
|
2457 |
|
|
if ((TP_REWCLOSE(dev)) && (status_bytes_rd | status_bytes_wr)) {
|
2458 |
|
|
tpqputs(TPQD_REWIND, "release: Doing rewind...");
|
2459 |
|
|
(void) do_qic_cmd(QCMD_REWIND, TIM_R);
|
2460 |
|
|
}
|
2461 |
|
|
|
2462 |
|
|
return;
|
2463 |
|
|
} /* qic02_tape_release */
|
2464 |
|
|
|
2465 |
|
|
|
2466 |
|
|
#ifdef CONFIG_QIC02_DYNCONF
|
2467 |
|
|
/* Set masks etc. based on the interface card type. */
|
2468 |
|
|
int update_ifc_masks(int ifc)
|
2469 |
|
|
{
|
2470 |
|
|
QIC02_TAPE_IFC = ifc;
|
2471 |
|
|
|
2472 |
|
|
if ((QIC02_TAPE_IFC == WANGTEK) || (QIC02_TAPE_IFC == EVEREX)) {
|
2473 |
|
|
QIC02_STAT_PORT = QIC02_TAPE_PORT;
|
2474 |
|
|
QIC02_CTL_PORT = QIC02_TAPE_PORT;
|
2475 |
|
|
QIC02_CMD_PORT = QIC02_TAPE_PORT+1;
|
2476 |
|
|
QIC02_DATA_PORT = QIC02_TAPE_PORT+1;
|
2477 |
|
|
QIC02_STAT_READY = WT_QIC02_STAT_READY;
|
2478 |
|
|
QIC02_STAT_EXCEPTION = WT_QIC02_STAT_EXCEPTION;
|
2479 |
|
|
QIC02_STAT_MASK = WT_QIC02_STAT_MASK;
|
2480 |
|
|
|
2481 |
|
|
QIC02_STAT_RESETMASK = WT_QIC02_STAT_RESETMASK;
|
2482 |
|
|
QIC02_STAT_RESETVAL = WT_QIC02_STAT_RESETVAL;
|
2483 |
|
|
|
2484 |
|
|
QIC02_CTL_RESET = WT_QIC02_CTL_RESET;
|
2485 |
|
|
QIC02_CTL_REQUEST = WT_QIC02_CTL_REQUEST;
|
2486 |
|
|
|
2487 |
|
|
if (QIC02_TAPE_DMA == 3)
|
2488 |
|
|
WT_CTL_DMA = WT_CTL_DMA3;
|
2489 |
|
|
else if (QIC02_TAPE_DMA == 1)
|
2490 |
|
|
WT_CTL_DMA = WT_CTL_DMA1;
|
2491 |
|
|
else {
|
2492 |
|
|
tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
|
2493 |
|
|
return -EIO;
|
2494 |
|
|
}
|
2495 |
|
|
|
2496 |
|
|
if (QIC02_TAPE_IFC == EVEREX) {
|
2497 |
|
|
/* Everex is a special case for Wangtek (actually
|
2498 |
|
|
* it's the other way 'round, but I saw Wangtek first)
|
2499 |
|
|
*/
|
2500 |
|
|
if (QIC02_TAPE_DMA==3)
|
2501 |
|
|
WT_CTL_DMA = WT_CTL_DMA1;
|
2502 |
|
|
/* Fixup the kernel copy of the IFC type to that
|
2503 |
|
|
* we don't have to distinguish between Wangtek and
|
2504 |
|
|
* and Everex at runtime.
|
2505 |
|
|
*/
|
2506 |
|
|
QIC02_TAPE_IFC = WANGTEK;
|
2507 |
|
|
}
|
2508 |
|
|
} else if (QIC02_TAPE_IFC == ARCHIVE) {
|
2509 |
|
|
QIC02_STAT_PORT = QIC02_TAPE_PORT+1;
|
2510 |
|
|
QIC02_CTL_PORT = QIC02_TAPE_PORT+1;
|
2511 |
|
|
QIC02_CMD_PORT = QIC02_TAPE_PORT;
|
2512 |
|
|
QIC02_DATA_PORT = QIC02_TAPE_PORT;
|
2513 |
|
|
QIC02_STAT_READY = AR_QIC02_STAT_READY;
|
2514 |
|
|
QIC02_STAT_EXCEPTION = AR_QIC02_STAT_EXCEPTION;
|
2515 |
|
|
QIC02_STAT_MASK = AR_QIC02_STAT_MASK;
|
2516 |
|
|
|
2517 |
|
|
QIC02_STAT_RESETMASK = AR_QIC02_STAT_RESETMASK;
|
2518 |
|
|
QIC02_STAT_RESETVAL = AR_QIC02_STAT_RESETVAL;
|
2519 |
|
|
|
2520 |
|
|
QIC02_CTL_RESET = AR_QIC02_CTL_RESET;
|
2521 |
|
|
QIC02_CTL_REQUEST = AR_QIC02_CTL_REQUEST;
|
2522 |
|
|
|
2523 |
|
|
if (QIC02_TAPE_DMA > 3) {
|
2524 |
|
|
tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
|
2525 |
|
|
return -EIO;
|
2526 |
|
|
}
|
2527 |
|
|
} else if (QIC02_TAPE_IFC == MOUNTAIN) {
|
2528 |
|
|
QIC02_STAT_PORT = QIC02_TAPE_PORT+1;
|
2529 |
|
|
QIC02_CTL_PORT = QIC02_TAPE_PORT+1;
|
2530 |
|
|
QIC02_CMD_PORT = QIC02_TAPE_PORT;
|
2531 |
|
|
QIC02_DATA_PORT = QIC02_TAPE_PORT;
|
2532 |
|
|
|
2533 |
|
|
QIC02_STAT_READY = MTN_QIC02_STAT_READY;
|
2534 |
|
|
QIC02_STAT_EXCEPTION = MTN_QIC02_STAT_EXCEPTION;
|
2535 |
|
|
QIC02_STAT_MASK = MTN_QIC02_STAT_MASK;
|
2536 |
|
|
|
2537 |
|
|
QIC02_STAT_RESETMASK = MTN_QIC02_STAT_RESETMASK;
|
2538 |
|
|
QIC02_STAT_RESETVAL = MTN_QIC02_STAT_RESETVAL;
|
2539 |
|
|
|
2540 |
|
|
QIC02_CTL_RESET = MTN_QIC02_CTL_RESET;
|
2541 |
|
|
QIC02_CTL_REQUEST = MTN_QIC02_CTL_REQUEST;
|
2542 |
|
|
|
2543 |
|
|
if (QIC02_TAPE_DMA > 3) {
|
2544 |
|
|
tpqputs(TPQD_ALWAYS, "Unsupported or incorrect DMA channel");
|
2545 |
|
|
return -EIO;
|
2546 |
|
|
}
|
2547 |
|
|
} else {
|
2548 |
|
|
tpqputs(TPQD_ALWAYS, "Invalid interface type");
|
2549 |
|
|
return -ENXIO;
|
2550 |
|
|
}
|
2551 |
|
|
return 0;
|
2552 |
|
|
} /* update_ifc-masks */
|
2553 |
|
|
#endif
|
2554 |
|
|
|
2555 |
|
|
|
2556 |
|
|
/* ioctl allows user programs to rewind the tape and stuff like that */
|
2557 |
|
|
static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
|
2558 |
|
|
unsigned int iocmd, unsigned long ioarg)
|
2559 |
|
|
{
|
2560 |
|
|
int error;
|
2561 |
|
|
short i;
|
2562 |
|
|
int dev_maj = MAJOR(inode->i_rdev);
|
2563 |
|
|
int c;
|
2564 |
|
|
struct mtop operation;
|
2565 |
|
|
char *stp, *argp;
|
2566 |
|
|
unsigned char blk_addr[6];
|
2567 |
|
|
struct mtpos ioctl_tell;
|
2568 |
|
|
|
2569 |
|
|
|
2570 |
|
|
if (TP_DIAGS(current_tape_dev))
|
2571 |
|
|
printk(TPQIC02_NAME ": ioctl(%4x, %4x, %4lx)\n", dev_maj, iocmd, ioarg);
|
2572 |
|
|
|
2573 |
|
|
if (!inode || !ioarg)
|
2574 |
|
|
return -EINVAL;
|
2575 |
|
|
|
2576 |
|
|
/* check iocmd first */
|
2577 |
|
|
|
2578 |
|
|
if (dev_maj != QIC02_TAPE_MAJOR) {
|
2579 |
|
|
printk(TPQIC02_NAME ": Oops! Wrong device?\n");
|
2580 |
|
|
/* A panic() would be appropriate here */
|
2581 |
|
|
return -ENODEV;
|
2582 |
|
|
}
|
2583 |
|
|
|
2584 |
|
|
c = iocmd & IOCCMD_MASK;
|
2585 |
|
|
|
2586 |
|
|
#ifdef DDIOCSDBG
|
2587 |
|
|
/* Check for DDI Debug Control, contributed by FvK, edited by HHB. */
|
2588 |
|
|
if (c == DDIOCSDBG) {
|
2589 |
|
|
if (!suser())
|
2590 |
|
|
return -EPERM;
|
2591 |
|
|
error = verify_area(VERIFY_READ, (int *) ioarg, sizeof(int));
|
2592 |
|
|
if (error) return error;
|
2593 |
|
|
c = get_user((int *) ioarg);
|
2594 |
|
|
if (c==0) {
|
2595 |
|
|
QIC02_TAPE_DEBUG = 0;
|
2596 |
|
|
return 0;
|
2597 |
|
|
}
|
2598 |
|
|
if ((c>=1) && (c<=32)) {
|
2599 |
|
|
QIC02_TAPE_DEBUG |= (1 << (c-1));
|
2600 |
|
|
return 0;
|
2601 |
|
|
}
|
2602 |
|
|
if (c >= 128) {
|
2603 |
|
|
QIC02_TAPE_DEBUG &= ~(1 << (c - 128));
|
2604 |
|
|
return 0;
|
2605 |
|
|
}
|
2606 |
|
|
return -EINVAL;
|
2607 |
|
|
}
|
2608 |
|
|
#endif
|
2609 |
|
|
|
2610 |
|
|
#ifdef CONFIG_QIC02_DYNCONF
|
2611 |
|
|
if (c == (MTIOCGETCONFIG & IOCCMD_MASK)) {
|
2612 |
|
|
if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtconfiginfo)) {
|
2613 |
|
|
tpqputs(TPQD_ALWAYS, "sizeof(struct mtconfiginfo) does not match!");
|
2614 |
|
|
return -EFAULT;
|
2615 |
|
|
}
|
2616 |
|
|
|
2617 |
|
|
/* check for valid user address */
|
2618 |
|
|
error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(qic02_tape_dynconf));
|
2619 |
|
|
if (error)
|
2620 |
|
|
return error;
|
2621 |
|
|
/* copy current settings to user space */
|
2622 |
|
|
stp = (char *) &qic02_tape_dynconf;
|
2623 |
|
|
argp = (char *) ioarg;
|
2624 |
|
|
for (i=0; i<sizeof(qic02_tape_dynconf); i++)
|
2625 |
|
|
put_user(*stp++, argp++);
|
2626 |
|
|
return 0;
|
2627 |
|
|
|
2628 |
|
|
} else if (c == (MTIOCSETCONFIG & IOCCMD_MASK)) {
|
2629 |
|
|
static int qic02_get_resources(void), qic02_release_resources(void);
|
2630 |
|
|
|
2631 |
|
|
/* One should always do a MTIOCGETCONFIG first, then update
|
2632 |
|
|
* user-settings, then write back with MTIOCSETCONFIG.
|
2633 |
|
|
* Re-open() the device before actual use to make sure
|
2634 |
|
|
* everything is initialized.
|
2635 |
|
|
*/
|
2636 |
|
|
if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtconfiginfo)) {
|
2637 |
|
|
tpqputs(TPQD_ALWAYS, "sizeof(struct mtconfiginfo) does not match!");
|
2638 |
|
|
return -EFAULT;
|
2639 |
|
|
}
|
2640 |
|
|
if (!suser())
|
2641 |
|
|
return -EPERM;
|
2642 |
|
|
if ((doing_read!=NO) || (doing_write!=NO))
|
2643 |
|
|
return -EBUSY;
|
2644 |
|
|
error = verify_area(VERIFY_READ, (char *) ioarg, sizeof(qic02_tape_dynconf));
|
2645 |
|
|
if (error)
|
2646 |
|
|
return error;
|
2647 |
|
|
|
2648 |
|
|
/* copy struct from user space to kernel space */
|
2649 |
|
|
stp = (char *) &qic02_tape_dynconf;
|
2650 |
|
|
argp = (char *) ioarg;
|
2651 |
|
|
for (i=0; i<sizeof(qic02_tape_dynconf); i++)
|
2652 |
|
|
*stp++ = get_user(argp++);
|
2653 |
|
|
if (status_zombie==NO)
|
2654 |
|
|
qic02_release_resources(); /* and go zombie */
|
2655 |
|
|
if (update_ifc_masks(qic02_tape_dynconf.ifc_type))
|
2656 |
|
|
return -EIO;
|
2657 |
|
|
if (qic02_get_resources())
|
2658 |
|
|
return -ENXIO;
|
2659 |
|
|
return 0;
|
2660 |
|
|
|
2661 |
|
|
}
|
2662 |
|
|
if (status_zombie==YES) {
|
2663 |
|
|
tpqputs(TPQD_ALWAYS, "Configs not set");
|
2664 |
|
|
return -ENXIO;
|
2665 |
|
|
}
|
2666 |
|
|
#endif
|
2667 |
|
|
if (c == (MTIOCTOP & IOCCMD_MASK)) {
|
2668 |
|
|
|
2669 |
|
|
/* Compare expected struct size and actual struct size. This
|
2670 |
|
|
* is useful to catch programs compiled with old #includes.
|
2671 |
|
|
*/
|
2672 |
|
|
if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtop)) {
|
2673 |
|
|
tpqputs(TPQD_ALWAYS, "sizeof(struct mtop) does not match!");
|
2674 |
|
|
return -EFAULT;
|
2675 |
|
|
}
|
2676 |
|
|
error = verify_area(VERIFY_READ, (char *) ioarg, sizeof(operation));
|
2677 |
|
|
if (error)
|
2678 |
|
|
return error;
|
2679 |
|
|
|
2680 |
|
|
/* copy mtop struct from user space to kernel space */
|
2681 |
|
|
stp = (char *) &operation;
|
2682 |
|
|
argp = (char *) ioarg;
|
2683 |
|
|
for (i=0; i<sizeof(operation); i++)
|
2684 |
|
|
*stp++ = get_user(argp++);
|
2685 |
|
|
|
2686 |
|
|
/* ---note: mt_count is signed, negative seeks must be
|
2687 |
|
|
* --- translated to seeks in opposite direction!
|
2688 |
|
|
* (only needed for Sun-programs, I think.)
|
2689 |
|
|
*/
|
2690 |
|
|
/* ---note: MTFSF with count 0 should position the
|
2691 |
|
|
* --- tape at the beginning of the current file.
|
2692 |
|
|
*/
|
2693 |
|
|
|
2694 |
|
|
if (TP_DIAGS(current_tape_dev))
|
2695 |
|
|
printk("OP op=%4x, count=%4x\n", operation.mt_op, operation.mt_count);
|
2696 |
|
|
|
2697 |
|
|
if (operation.mt_count < 0)
|
2698 |
|
|
tpqputs(TPQD_ALWAYS, "Warning: negative mt_count ignored");
|
2699 |
|
|
|
2700 |
|
|
ioctl_status.mt_resid = operation.mt_count;
|
2701 |
|
|
if (operation.mt_op == MTSEEK) {
|
2702 |
|
|
if (!TP_HAVE_SEEK)
|
2703 |
|
|
return -ENOTTY;
|
2704 |
|
|
seek_addr_buf[0] = (operation.mt_count>>16)&0xff;
|
2705 |
|
|
seek_addr_buf[1] = (operation.mt_count>>8)&0xff;
|
2706 |
|
|
seek_addr_buf[2] = (operation.mt_count)&0xff;
|
2707 |
|
|
if (operation.mt_count>>24)
|
2708 |
|
|
return -EINVAL;
|
2709 |
|
|
if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
|
2710 |
|
|
return error;
|
2711 |
|
|
ioctl_status.mt_resid = 0;
|
2712 |
|
|
} else {
|
2713 |
|
|
while (operation.mt_count > 0) {
|
2714 |
|
|
operation.mt_count--;
|
2715 |
|
|
if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
|
2716 |
|
|
return error;
|
2717 |
|
|
ioctl_status.mt_resid = operation.mt_count;
|
2718 |
|
|
}
|
2719 |
|
|
}
|
2720 |
|
|
return 0;
|
2721 |
|
|
|
2722 |
|
|
} else if (c == (MTIOCGET & IOCCMD_MASK)) {
|
2723 |
|
|
if (TP_DIAGS(current_tape_dev))
|
2724 |
|
|
printk("GET ");
|
2725 |
|
|
|
2726 |
|
|
/* compare expected struct size and actual struct size */
|
2727 |
|
|
if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtget)) {
|
2728 |
|
|
tpqputs(TPQD_ALWAYS, "sizeof(struct mtget) does not match!");
|
2729 |
|
|
return -EFAULT;
|
2730 |
|
|
}
|
2731 |
|
|
|
2732 |
|
|
/* check for valid user address */
|
2733 |
|
|
error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(ioctl_status));
|
2734 |
|
|
if (error)
|
2735 |
|
|
return error;
|
2736 |
|
|
|
2737 |
|
|
/* It appears (gmt(1)) that it is normal behaviour to
|
2738 |
|
|
* first set the status with MTNOP, and then to read
|
2739 |
|
|
* it out with MTIOCGET
|
2740 |
|
|
*/
|
2741 |
|
|
|
2742 |
|
|
/* copy results to user space */
|
2743 |
|
|
stp = (char *) &ioctl_status;
|
2744 |
|
|
argp = (char *) ioarg;
|
2745 |
|
|
for (i=0; i<sizeof(ioctl_status); i++)
|
2746 |
|
|
put_user(*stp++, argp++);
|
2747 |
|
|
return 0;
|
2748 |
|
|
|
2749 |
|
|
|
2750 |
|
|
} else if (TP_HAVE_TELL && (c == (MTIOCPOS & IOCCMD_MASK))) {
|
2751 |
|
|
if (TP_DIAGS(current_tape_dev))
|
2752 |
|
|
printk("POS ");
|
2753 |
|
|
|
2754 |
|
|
/* compare expected struct size and actual struct size */
|
2755 |
|
|
if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtpos)) {
|
2756 |
|
|
tpqputs(TPQD_ALWAYS, "sizeof(struct mtpos) does not match!");
|
2757 |
|
|
return -EFAULT;
|
2758 |
|
|
}
|
2759 |
|
|
|
2760 |
|
|
/* check for valid user address */
|
2761 |
|
|
error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(ioctl_tell));
|
2762 |
|
|
if (error)
|
2763 |
|
|
return error;
|
2764 |
|
|
|
2765 |
|
|
tpqputs(TPQD_IOCTLS, "MTTELL reading block address");
|
2766 |
|
|
if ((doing_read==YES) || (doing_write==YES))
|
2767 |
|
|
finish_rw(AR_QCMDV_TELL_BLK);
|
2768 |
|
|
|
2769 |
|
|
c = rdstatus((char *) blk_addr, sizeof(blk_addr), AR_QCMDV_TELL_BLK);
|
2770 |
|
|
if (c!=TE_OK)
|
2771 |
|
|
return -EIO;
|
2772 |
|
|
|
2773 |
|
|
ioctl_tell.mt_blkno = (blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5];
|
2774 |
|
|
|
2775 |
|
|
/* copy results to user space */
|
2776 |
|
|
stp = (char *) &ioctl_tell;
|
2777 |
|
|
argp = (char *) ioarg;
|
2778 |
|
|
for (i=0; i<sizeof(ioctl_tell); i++)
|
2779 |
|
|
put_user(*stp++, argp++);
|
2780 |
|
|
return 0;
|
2781 |
|
|
|
2782 |
|
|
} else
|
2783 |
|
|
return -ENOTTY; /* Other cmds not supported. */
|
2784 |
|
|
} /* qic02_tape_ioctl */
|
2785 |
|
|
|
2786 |
|
|
|
2787 |
|
|
|
2788 |
|
|
/* These are (most) of the interface functions: */
|
2789 |
|
|
static struct file_operations qic02_tape_fops = {
|
2790 |
|
|
qic02_tape_lseek, /* not allowed */
|
2791 |
|
|
qic02_tape_read, /* read */
|
2792 |
|
|
qic02_tape_write, /* write */
|
2793 |
|
|
NULL, /* readdir not allowed */
|
2794 |
|
|
NULL, /* select ??? */
|
2795 |
|
|
qic02_tape_ioctl, /* ioctl */
|
2796 |
|
|
NULL, /* mmap not allowed */
|
2797 |
|
|
qic02_tape_open, /* open */
|
2798 |
|
|
qic02_tape_release, /* release */
|
2799 |
|
|
NULL, /* fsync */
|
2800 |
|
|
NULL, /* fasync */
|
2801 |
|
|
NULL, /* check_media_change */
|
2802 |
|
|
NULL /* revalidate */
|
2803 |
|
|
};
|
2804 |
|
|
|
2805 |
|
|
/* align `a' at `size' bytes. `size' must be a power of 2 */
|
2806 |
|
|
static inline unsigned long const align_buffer(unsigned long a, unsigned size)
|
2807 |
|
|
{
|
2808 |
|
|
if (a & (size-1)) /* if not aligned */
|
2809 |
|
|
return (a | (size-1)) + 1;
|
2810 |
|
|
else /* else is aligned */
|
2811 |
|
|
return a;
|
2812 |
|
|
}
|
2813 |
|
|
|
2814 |
|
|
|
2815 |
|
|
|
2816 |
|
|
static void qic02_release_resources(void)
|
2817 |
|
|
{
|
2818 |
|
|
free_irq(QIC02_TAPE_IRQ, NULL);
|
2819 |
|
|
free_dma(QIC02_TAPE_DMA);
|
2820 |
|
|
status_zombie = YES;
|
2821 |
|
|
} /* qic02_release_resources */
|
2822 |
|
|
|
2823 |
|
|
|
2824 |
|
|
|
2825 |
|
|
|
2826 |
|
|
static int qic02_get_resources(void)
|
2827 |
|
|
{
|
2828 |
|
|
/* First perform some checks. If one of them fails,
|
2829 |
|
|
* the tape driver will not be registered to the system.
|
2830 |
|
|
*/
|
2831 |
|
|
if (QIC02_TAPE_IRQ>16) {
|
2832 |
|
|
tpqputs(TPQD_ALWAYS, "Bogus interrupt number.");
|
2833 |
|
|
return -1;
|
2834 |
|
|
}
|
2835 |
|
|
|
2836 |
|
|
/* for DYNCONF, allocating DMA & IRQ should not be done until
|
2837 |
|
|
* the config parameters have been set using MTSETCONFIG.
|
2838 |
|
|
*/
|
2839 |
|
|
|
2840 |
|
|
/* get IRQ */
|
2841 |
|
|
if (request_irq(QIC02_TAPE_IRQ, qic02_tape_interrupt, SA_INTERRUPT, "QIC-02", NULL)) {
|
2842 |
|
|
printk(TPQIC02_NAME ": can't allocate IRQ%d for QIC-02 tape\n",
|
2843 |
|
|
QIC02_TAPE_IRQ);
|
2844 |
|
|
status_zombie = YES;
|
2845 |
|
|
return -1;
|
2846 |
|
|
}
|
2847 |
|
|
|
2848 |
|
|
/* After IRQ, allocate DMA channel */
|
2849 |
|
|
if (request_dma(QIC02_TAPE_DMA,"QIC-02")) {
|
2850 |
|
|
printk(TPQIC02_NAME ": can't allocate DMA%d for QIC-02 tape\n",
|
2851 |
|
|
QIC02_TAPE_DMA);
|
2852 |
|
|
free_irq(QIC02_TAPE_IRQ, NULL);
|
2853 |
|
|
status_zombie = YES;
|
2854 |
|
|
return -1;
|
2855 |
|
|
}
|
2856 |
|
|
|
2857 |
|
|
printk(TPQIC02_NAME ": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n",
|
2858 |
|
|
QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
|
2859 |
|
|
((QIC02_TAPE_IFC==ARCHIVE) || (QIC02_TAPE_IFC==MOUNTAIN))?
|
2860 |
|
|
QIC02_CMD_PORT : QIC02_STAT_PORT,
|
2861 |
|
|
(QIC02_TAPE_IFC==MOUNTAIN)? "Mountain" :
|
2862 |
|
|
((QIC02_TAPE_IFC==ARCHIVE)? "Archive" : "Wangtek"));
|
2863 |
|
|
|
2864 |
|
|
if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK) {
|
2865 |
|
|
/* No drive detected, so vanish */
|
2866 |
|
|
tpqputs(TPQD_ALWAYS, "No drive detected -- releasing irq and dma.");
|
2867 |
|
|
status_dead = YES;
|
2868 |
|
|
qic02_release_resources();
|
2869 |
|
|
return -1;
|
2870 |
|
|
}
|
2871 |
|
|
|
2872 |
|
|
/* All should be ok now */
|
2873 |
|
|
status_zombie = NO;
|
2874 |
|
|
return 0;
|
2875 |
|
|
} /* qic02_get_resources */
|
2876 |
|
|
|
2877 |
|
|
|
2878 |
|
|
int qic02_tape_init(void)
|
2879 |
|
|
/* Shouldn't this be a caddr_t ? */
|
2880 |
|
|
{
|
2881 |
|
|
|
2882 |
|
|
if (TPSTATSIZE != 6) {
|
2883 |
|
|
printk(TPQIC02_NAME ": internal error: tpstatus struct incorrect!\n");
|
2884 |
|
|
return -ENODEV;
|
2885 |
|
|
}
|
2886 |
|
|
if ((TPQBUF_SIZE<512) || (TPQBUF_SIZE>=0x10000)) {
|
2887 |
|
|
printk(TPQIC02_NAME ": internal error: DMA buffer size out of range\n");
|
2888 |
|
|
return -ENODEV;
|
2889 |
|
|
}
|
2890 |
|
|
|
2891 |
|
|
QIC02_TAPE_DEBUG = TPQD_DEFAULT_FLAGS;
|
2892 |
|
|
|
2893 |
|
|
current_tape_dev = MKDEV(QIC02_TAPE_MAJOR, 0);
|
2894 |
|
|
|
2895 |
|
|
#ifndef CONFIG_QIC02_DYNCONF
|
2896 |
|
|
printk(TPQIC02_NAME ": IRQ %d, DMA %d, IO 0x%x, IFC %s, %s, %s\n",
|
2897 |
|
|
QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
|
2898 |
|
|
# if QIC02_TAPE_IFC == WANGTEK
|
2899 |
|
|
QIC02_STAT_PORT, "Wangtek",
|
2900 |
|
|
# elif QIC02_TAPE_IFC == ARCHIVE
|
2901 |
|
|
QIC02_CMD_PORT, "Archive",
|
2902 |
|
|
# elif QIC02_TAPE_IFC == MOUNTAIN
|
2903 |
|
|
QIC02_CMD_PORT, "Mountain",
|
2904 |
|
|
# else
|
2905 |
|
|
# error
|
2906 |
|
|
# endif
|
2907 |
|
|
rcs_revision, rcs_date);
|
2908 |
|
|
if (qic02_get_resources())
|
2909 |
|
|
return -ENODEV;
|
2910 |
|
|
#else
|
2911 |
|
|
printk(TPQIC02_NAME ": Runtime config, %s, %s\n",
|
2912 |
|
|
rcs_revision, rcs_date);
|
2913 |
|
|
|
2914 |
|
|
QIC02_TAPE_IRQ = BOGUS_IRQ; /* invalid value */
|
2915 |
|
|
#endif
|
2916 |
|
|
|
2917 |
|
|
printk(TPQIC02_NAME ": DMA buffers: %u blocks", NR_BLK_BUF);
|
2918 |
|
|
|
2919 |
|
|
/* Setup the page-address for the dma transfer.
|
2920 |
|
|
* This assumes a one-to-one identity mapping between
|
2921 |
|
|
* kernel addresses and physical memory.
|
2922 |
|
|
*/
|
2923 |
|
|
buffaddr = align_buffer((unsigned long) &qic02_tape_buf, TAPE_BLKSIZE);
|
2924 |
|
|
printk(", at address 0x%lx (0x%lx)\n", buffaddr, (unsigned long) &qic02_tape_buf);
|
2925 |
|
|
|
2926 |
|
|
#ifndef CONFIG_MAX_16M
|
2927 |
|
|
if (buffaddr+TPQBUF_SIZE>=0x1000000) {
|
2928 |
|
|
printk(TPQIC02_NAME ": DMA buffer *must* be in lower 16MB\n");
|
2929 |
|
|
return -ENODEV;
|
2930 |
|
|
}
|
2931 |
|
|
#endif
|
2932 |
|
|
|
2933 |
|
|
/* If we got this far, install driver functions */
|
2934 |
|
|
if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops)) {
|
2935 |
|
|
printk(TPQIC02_NAME ": Unable to get chrdev major %d\n", QIC02_TAPE_MAJOR);
|
2936 |
|
|
#ifndef CONFIG_QIC02_DYNCONF
|
2937 |
|
|
free_irq(QIC02_TAPE_IRQ, NULL);
|
2938 |
|
|
free_dma(QIC02_TAPE_DMA);
|
2939 |
|
|
#endif
|
2940 |
|
|
return -ENODEV;
|
2941 |
|
|
}
|
2942 |
|
|
|
2943 |
|
|
/* prepare timer */
|
2944 |
|
|
TIMEROFF;
|
2945 |
|
|
timer_table[QIC02_TAPE_TIMER].expires = 0;
|
2946 |
|
|
timer_table[QIC02_TAPE_TIMER].fn = qic02_tape_times_out;
|
2947 |
|
|
|
2948 |
|
|
#ifndef CONFIG_QIC02_DYNCONF
|
2949 |
|
|
if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK) {
|
2950 |
|
|
/* No drive detected, so vanish */
|
2951 |
|
|
tpqputs(TPQD_ALWAYS, "No drive detected -- driver going on vacation...");
|
2952 |
|
|
status_dead = YES;
|
2953 |
|
|
free_irq(QIC02_TAPE_IRQ, NULL);
|
2954 |
|
|
free_dma(QIC02_TAPE_DMA);
|
2955 |
|
|
unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
|
2956 |
|
|
return -ENODEV;
|
2957 |
|
|
} else {
|
2958 |
|
|
if (is_exception()) {
|
2959 |
|
|
tpqputs(TPQD_ALWAYS, "exception detected\n");
|
2960 |
|
|
(void) tp_sense(TP_WRP|TP_POR|TP_CNI);
|
2961 |
|
|
}
|
2962 |
|
|
}
|
2963 |
|
|
#endif
|
2964 |
|
|
|
2965 |
|
|
/* initialize generic status for ioctl requests */
|
2966 |
|
|
|
2967 |
|
|
ioctl_status.mt_type = QIC02_TAPE_DRIVE; /* MT_IS* id nr */
|
2968 |
|
|
|
2969 |
|
|
ioctl_status.mt_resid = 0; /* ---residual count */
|
2970 |
|
|
ioctl_status.mt_gstat = 0; /* ---generic status */
|
2971 |
|
|
ioctl_status.mt_erreg = 0; /* not used */
|
2972 |
|
|
ioctl_status.mt_fileno = 0; /* number of current file on tape */
|
2973 |
|
|
ioctl_status.mt_blkno = 0; /* number of current (logical) block */
|
2974 |
|
|
|
2975 |
|
|
return 0;
|
2976 |
|
|
} /* qic02_tape_init */
|
2977 |
|
|
|